R notebook for statistical analysis of the sacc-tDCS dataset. Previous processing:

  • Raw data were parsed into events (saccades, fixations, etc.) by the EyeLink data were collected on.
  • Events were extracted and saccade measures were computed with a MATLAB script.
# Load some libraries
library("dplyr") # wrangling data frame data
library("tidyr") # tidying data frames
library("ggplot2") # plotting
library("ez") # ANOVA
library("knitr") # R markdown output (html, pdf, etc.)
library("BayesFactor") # Bayesian statistics
library("retimes") # Ex-Gaussian reaction time distributions

Questionnaires

PANAS

Load data

In each session of the experiment, participants completed the Positive and Negative Affect Scale (PANAS) twice:

  1. Pre-measurement: Before starting setup of the tDCS and eye tracker
  2. Post-measurement: After the electrodes were removed following task completion

As most participants were native Dutch speakers, we also used a Dutch language version of the PANAS, as reported by Engelen et al. (2006).

# Load the data frame
dataFile <- file.path("data", "PANAS.csv")
panasData <- read.csv(dataFile, header = TRUE, sep = ";")
panasData$time <- factor(panasData$time, levels = c("pre","post")) # reorder levels chronologically instead of alphabetically
head(panasData) # show data frame

Factors:

  • subject: subject ID (S01, S02, etc)
  • session: Whether data are from the first or second session
  • stimulation: Whether data are from the anodal or cathodal session
  • time: Whether data are from the pre or post measurement

DATA:

The PANAS contains 20 items, split equally into positive and negative affect. Each item is rated on a Likert scale:

  1. very slightly or not at all
  2. a little
  3. moderately
  4. quite a bit
  5. extremely

To obtain a positive affect score, we sum items: 1 (interested), 3 (excited), 5 (strong), 9 (enthusiastic), 10 (proud), 12 (alert), 14 (inspired), 16 (determined), 17 (attentive) and 19 (active).

To obtain a negative affect score, we sum items: 2 (distressed), 4 (upset), 6 (guilty), 7 (scared), 8 (hostile), 11 (irritable), 13 (ashamed), 15 (nervous), 18 (jittery) and 20 (afraid).

Post-pre differences per item

panasPrePost <- panasData %>%
  group_by(subject,session,stimulation) %>% # for each subject, session, stimulation combination
  select(-time) %>% # don't do subtraction for this column
  summarise_each(funs(diff(.))) # subtract pre and post

Let’s plot the post-pre differences for each item, split for stimulation session.

panasPrePost %>%
  gather(item, score, pos.1.interested:neg.20.afraid) %>% # gather all PANAS columns so it can be used as a factor
  ggplot(aes(item, score)) +
      stat_summary(fun.y = mean, geom = "point", position = position_dodge(width = 0.6), aes(color = stimulation)) +
      geom_hline(yintercept = 0, linetype = "dashed") +
      coord_cartesian(ylim = c(-1,1)) +
      theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

Most scores become negative, meaning the post score was smaller than pre. So they generally feel “less” of everything. This seems particularly the case for positive affect, although participants do feel slightly more proud, determined, and strong.

They become particularly less jittery, nervous, irritable, and also less attentive, active, and excited.

The biggest differences between the sessions are in the positive items, except for irritable.

For some positive items, anodal stimulation results in a more positive score, while cathodal reesults in a more negative score: alert, inspired, determined, and strong.

Composite positive/negative scores

panasComposite <- panasData %>% 
  mutate(positive = rowSums(select(., contains("pos")))) %>% # sum all the positive scores together
  mutate(negative = rowSums(select(., contains("neg")))) %>% # sum all the negative scores together
  select(subject:time, positive, negative) %>% # drop the original PANAS columns
  gather(affect, score, positive, negative) # gather affect so it can be used as a factor
ggplot(panasComposite, aes(time,score, color = stimulation)) +
facet_wrap(~affect) +
  geom_point(position = position_jitter(width = 0.5)) +
  stat_summary(fun.data = mean_cl_normal, position = position_dodge(width = 1))

The negative scores are much lower than the positive overall.

The pre to post differences are larger for positive scores, particularly for the cathodal session.

Statistics: positive scores

Repeated measures ANOVA with factors STIMULATION (anodal vs. cathodal) and TIME (pre vs. post)

panasCompositePositive <- filter(panasComposite, affect == "positive") # new data frame with only positive scores
modelPositive <- ezANOVA(data = data.frame(panasCompositePositive), # Repeated over subjects; type 3 sums of squares (cf. SPSS)
                        dv = .(score), wid = .(subject), within = .(stimulation, time), type = 3)
kable(modelPositive)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 14 0.9180942 0.3542315 0.0080119
3 time 1 14 10.2831973 0.0063350 * 0.0496325
4 stimulation:time 1 14 7.3652913 0.0167928 * 0.0168597

Subjects’ mood becomes less positive after stimulation, particularly in the cathodal session

Statistics: negative scores

Repeated measures ANOVA with factors STIMULATION (anodal vs. cathodal) and TIME (pre vs. post)

panasCompositeNegative <- filter(panasComposite, affect == "negative") # new data frame with only negative scores
modelNegative <- ezANOVA(data = data.frame(panasCompositeNegative), # Repeated over subjects; type 3 sums of squares (cf. SPSS)
                        dv = .(score), wid = .(subject), within = .(stimulation, time), type = 3)
kable(modelNegative)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 14 0.1054217 0.7502187 0.0007105
3 time 1 14 16.2682403 0.0012327 * 0.0845895
4 stimulation:time 1 14 3.8757669 0.0691122 0.0101630

Subjects’ mood also become less negative after stimulation…

tDCS sensations

After each session, subjects also completed a questionnaire probing tDCS sensations.

Load data

# Load the data frame
dataFile <- file.path("data", "tdcs_sensations.csv")
sensData <- read.csv(dataFile, header = TRUE, sep = ";", na.strings = "")
head(sensData) # show data frame

They were asked to which degree the following sensations were present during stimulation: tingling, itching sensation, burning sensation, pain, headache, fatigue, dizziness and nausea. Each was rated on a scale from 0-4:

  1. none
  2. a little
  3. moderate
  4. strong
  5. very strong

They also rated their confidence that the sensations were caused by the stimulation on a scale from 0-4 (columns starting with conf.):

  1. n/a (meaning they rated the sensation a 0 on the previous scale)
  2. unlikely
  3. possibly
  4. likely
  5. very likely

Finally, they filled in whether they felt one electrode more than the other (felt.more); (and if so, which and for which sensations).

Factors:

  • subject: subject ID (S01, S02, etc)
  • session: Whether data are from the first or second session
  • stimulation: Whether data are from the anodal or cathodal session

Plot sensation distribution

sensData %>%
  select(everything(), -contains("conf"), -felt.more) %>% # drop the confidence columns
  gather(sensation, rating, itching:nausea) %>% # gather sensations so they can be used as a factor
  ggplot(aes(rating, fill = stimulation)) +
    facet_wrap(~sensation) +
    geom_histogram(position = "dodge", binwidth = 0.5) +
    xlim(0.5,4.5) +
    ggtitle("Sensations over 15 anodal sessions, 15 cathodal sessions")

Nausea was never experienced; dizziness and pain are also rare, and mild.

Burning, itching and tingling are most frequently experienced and to a higher degree.

Plot confidence distributions

sensData %>%
  select(contains("conf"), subject, session, stimulation) %>% # drop the rating columns
  gather(sensation, rating, conf.itching:conf.nausea) %>%
  ggplot(aes(rating, fill = stimulation)) +
    facet_wrap(~sensation) +
    geom_histogram(position = "dodge", binwidth = 0.5) +
    xlim(0.5,4.5) +
    ggtitle("Confidence over 15 anodal sessions, 15 cathodal sessions")

For “local” sensations like burning, tingling and dizziness, subjects have high confidence that these are due to tDCS. For more diffuse sensations, like fatigue and headache, ratings are very low, so their occurence might just be due to performing the task for an extended period of time.

Sensation difference between anode and cathode

sensData %>%
  select(felt.more, subject, session, stimulation) %>% # keep only the relevant column
  mutate(felt.more = factor(felt.more, levels = c("anode", "equal", "cathode"))) %>% # keep colors consistent
  ggplot(aes(stimulation, fill = felt.more)) +
    geom_bar() +
  scale_y_continuous(breaks = 1:15)

There’s a pretty even split between which electrode people feel the most, so there don’t appear to be worrisome biases.

During anodal stimulation, the anode is felt more than the cathode; during cathodal stimulation the cathode is felt more than the anode. In other words, the electrode over the FEF is always felt more than the forehead electrode.

About a third of people did not indicate they felt one more than the other; this is slightly more in the cathodal session.

Statistics

We will test for every sensation separately whether there was a difference between the anodal and cathodal sessions. Mann-Whitney-U tests are most appropriate here, as the data are ordinal (Likert) and do not look normally distributed.

Itching

wilcox.test(sensData$itching[sensData$stimulation == "anodal"], sensData$itching[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$itching[sensData$stimulation == "anodal"] and sensData$itching[sensData$stimulation == "cathodal"]
W = 122, p-value = 0.6828
alternative hypothesis: true location shift is not equal to 0

Tingling

wilcox.test(sensData$tingling[sensData$stimulation == "anodal"], sensData$tingling[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$tingling[sensData$stimulation == "anodal"] and sensData$tingling[sensData$stimulation == "cathodal"]
W = 93, p-value = 0.4097
alternative hypothesis: true location shift is not equal to 0

Burning

wilcox.test(sensData$burning[sensData$stimulation == "anodal"], sensData$burning[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$burning[sensData$stimulation == "anodal"] and sensData$burning[sensData$stimulation == "cathodal"]
W = 79.5, p-value = 0.1571
alternative hypothesis: true location shift is not equal to 0

Pain

wilcox.test(sensData$pain[sensData$stimulation == "anodal"], sensData$pain[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$pain[sensData$stimulation == "anodal"] and sensData$pain[sensData$stimulation == "cathodal"]
W = 94, p-value = 0.3126
alternative hypothesis: true location shift is not equal to 0

Headache

wilcox.test(sensData$headache[sensData$stimulation == "anodal"], sensData$headache[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$headache[sensData$stimulation == "anodal"] and sensData$headache[sensData$stimulation == "cathodal"]
W = 118, p-value = 0.7782
alternative hypothesis: true location shift is not equal to 0

Fatigue

wilcox.test(sensData$fatigue[sensData$stimulation == "anodal"], sensData$fatigue[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$fatigue[sensData$stimulation == "anodal"] and sensData$fatigue[sensData$stimulation == "cathodal"]
W = 100, p-value = 0.5757
alternative hypothesis: true location shift is not equal to 0

Dizziness

wilcox.test(sensData$dizziness[sensData$stimulation == "anodal"], sensData$dizziness[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$dizziness[sensData$stimulation == "anodal"] and sensData$dizziness[sensData$stimulation == "cathodal"]
W = 105.5, p-value = 0.6045
alternative hypothesis: true location shift is not equal to 0

Nausea

wilcox.test(sensData$nausea[sensData$stimulation == "anodal"], sensData$nausea[sensData$stimulation == "cathodal"])
cannot compute exact p-value with ties

    Wilcoxon rank sum test with continuity correction

data:  sensData$nausea[sensData$stimulation == "anodal"] and sensData$nausea[sensData$stimulation == "cathodal"]
W = 112.5, p-value = NA
alternative hypothesis: true location shift is not equal to 0

Nausea was rated 0 by everyone for both anodal and cathodal.

Load eye data

The .csv file with the eye tracking data was created in MATLAB.

# Load the data frame
dataFile <- file.path("data", "sacc-tDCS_data.csv")
groupData <- read.csv(dataFile, header = TRUE, na.strings = "NaN")
# Format data frame
groupData <- select(groupData, -X) # drop final empty column named "X"
groupData$leg <- factor(groupData$leg, levels = c("pre", "tDCS", "post"))
kable(head(groupData))
subject stimulation leg block trial type direction deviation.start deviation.end amplitude latency
S01 anodal pre 1 1 lateral right 0.462897 0.170648 8.02463 433
S01 anodal pre 1 1 center left 0.459092 1.035020 7.16262 439
S01 anodal pre 1 2 lateral right 0.344561 0.409786 7.74873 291
S01 anodal pre 1 2 center left 0.550230 0.505107 7.43233 198
S01 anodal pre 1 3 lateral right 0.514736 0.612098 7.61080 281
S01 anodal pre 1 3 center left 0.620728 1.627990 6.35043 376
  • subject: subject IDj
  • stimulation: Whether data are from the anodal or cathodal session
  • leg: Whether data are before (pre), during (tDCS), or after (post) tDCS
  • block: After each block participant had a brief break and tracker was recalibrated
  • trial: trial number within a block
  • type:
    • lateral - fixation in center of display, saccade made towards the periphery
    • center - fixation in periphery, saccade made back towards the center of the display
  • direction: left for saccades towards the left of current fixation position; right for saccades to the right
  • deviation.start : distance (in visual angle) from saccade start point to fixation
  • deviation.end: distance (in visual angle) from saccade end point to target location
  • amplitude: distance (in visual angle) between saccade start and end point
  • latency: time (in ms) from target onset to start of saccade

Basic inspection

Reaction time distributions

Histograms for each subject

histType <- ggplot(groupData, aes(latency, fill = type)) +
  facet_wrap(~subject, nrow = 3, scales ="free_y") +
  geom_histogram(binwidth = 5, color = "grey50", size = .2) +
  xlim(-50,300)
histType

Stray observations:

  • Center saccades are much faster than lateral, though not to the same degree in all subjects
  • Some have a fat short latency tail - too fast saccades that are virtually all towards the center: S05, S10, S11
  • Some appear bimodal, but when split for type this is generally because center saccades are faster: S05, S06, S11
  • Some are super sharp (S8); others really broad (S01)
  • S01 has a very typical looking distribution, but slow

Stimulation effects across subjects

dens <- ggplot(groupData, aes(latency, color = stimulation, linetype = leg)) +
  facet_grid(type ~ direction) +
  geom_density() +
  xlim(0, 250) +
  scale_color_brewer(palette = "Set1")
dens

Anodal vs. cathodal in each subject

denstDCS <- ggplot(groupData[groupData$leg == 'tDCS' & groupData$type == "lateral", ], aes(latency, color = stimulation)) +
  facet_wrap(~subject, nrow = 3, scales ="free_y") +
  geom_density() +
  xlim(0, 250) +
  scale_color_brewer(palette = "Set1") +
  ggtitle('Lateral saccades, tDCS block')
denstDCS

Anodal session in each subject

densLegAnodal <- ggplot(groupData[groupData$stimulation == 'anodal' & groupData$type == "lateral", ], aes(latency, color = leg)) +
  facet_wrap(~subject, nrow = 3, scales ="free_y") +
  geom_density() +
  xlim(0, 250) +
  ggtitle('Lateral saccades, anodal')
densLegAnodal

Cathodal session in each subject

densLegCathodal <- ggplot(groupData[groupData$stimulation == 'cathodal' & groupData$type == "lateral", ], aes(latency, color = leg)) +
  facet_wrap(~subject, nrow = 3, scales ="free_y") +
  geom_density() +
  xlim(0, 250) +
  ggtitle('Lateral saccades, cathodal')
densLegCathodal

Outliers

Mark outliers

Criteria for outliers:

  • Discard fast saccades, with a latency of 50 ms or less
  • Discard slow saccades, saccades with a latency of 400 ms or more
  • Discard inaccurate fixations, with saccade starting point more than 1.8 degrees or more away from fixation
  • Discard faulty saccades, with saccade end point more than 8 degree or more away from the target

In Kanai et al. (2012), this was:

  • Fast saccades: 50 ms
  • Slow saccades: 400 ms
  • Bad fixations: 1.8 degrees
  • Faulty saccades: opposite hemifield of target (here, that would be 8 degrees as targets were that eccentric)
# Mark outliers
groupData <- mutate(groupData, outlier = FALSE, # fill vector with FALSE for all trials
                    outlier = ifelse(latency < tooFast, "fast", outlier), # mark too fast trials as "fast"
                    outlier = ifelse(latency > tooSlow, "slow", outlier), # mark too slow trials as "slow"
                    outlier = ifelse(deviation.start > badFix, "fixation", outlier), # mark bad fixations as "fixation"
                    outlier = ifelse(deviation.end > badSacc, "saccade", outlier)) # mark inaccurate saccades as "saccade"
groupDataClean <- filter(groupData, outlier == FALSE) # make new data frame without outlier trials

Plot outliers per subject

outlierPlot <- ggplot(groupData[groupData$outlier != FALSE, ], aes(interaction(stimulation,leg,block,trial), latency, color = outlier, shape = type)) +
  facet_wrap(~subject, nrow = 4, scales = "free_y") +
  geom_point() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = tooFast, linetype = "dashed") +
  geom_hline(yintercept = tooSlow, linetype = "dashed") +
  xlab('Trial') +
  theme(axis.text.x=element_blank(), # remove x-axis (just trial count)
  axis.ticks.x=element_blank())
outlierPlot

outlierCount <- groupData %>%
  group_by(subject) %>%
  summarize(outlier_count = sum(outlier != FALSE, na.rm = TRUE))
kable(outlierCount, caption = "Number of outlier trials per subject")
subject outlier_count
S01 180
S02 35
S03 282
S04 154
S05 536
S06 432
S07 48
S08 180
S09 116
S10 730
S11 303
S12 101
S13 176
S14 426
S15 155
S16 1026
S17 394
S18 28
S19 289
S20 383

Stray observations:

Differences between subjects:

  • Some subjects have barely any outliers (S02, S07)
  • Most subjects have quite a few outliers, especially S05,S06, S10 and S1. The mean is 299 out of 5760 trials in total
  • Only S01 has a sizable amount of slow saccades
  • S14 has a lot of negative latencies (and also long positive latencies)
  • Those subjects with many fast saccades also tend to have many bad fixations (S06, S10, but see S08)

General patterns:

  • Occurence of outliers seems stable throughout the session: there aren’t more/less in the beginning / end
  • There are very few inaccurate saccades (makes sense, because task is easy and criterion is not strict)
  • Most outliers are too fast saccades and bad fixations
  • Slow saccades are lateral, fast saccades are to the center, because only the latter are predictable
  • Bad fixations appear to be mostly center saccades (but this varies a lot). Perhaps the eyes already drift back towards the center, before executing the saccade?
  • Or is the source of bad fixations simply poor quality of the eye tracker data? e.g. people are actually fixating, but due to drift it appears they are not.

Median reaction time

Here we simply extract median RTs for each condition and use a repeated measures ANOVA for statistical analysis, following Kanai et al. (2012).

Data per block

# Compute median in each condition
latencyMedian <- groupDataClean %>%
  group_by(subject,stimulation,leg,block,type,direction) %>%
  summarise(latency = median(latency, na.rm = TRUE))

Full factorial plot

# Plot out all the data
fullPlot <- ggplot(latencyMedian, aes(interaction(block,leg), latency, color = stimulation, shape = stimulation)) +
  facet_grid(type ~ direction) +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1)
fullPlot

There is a pretty sizable difference between the anodal & cathodal sessions in the baseline already: cathodal is always faster than anodal.

The above plot also shows a lot of variability, so it might be best to average over each 3 consecutive blocks so the data come in 15-minute intervals.

15-minute intervals (collapse 3 blocks)

# Compute median per leg
latencyMedianLeg <- groupDataClean %>%
  group_by(subject,stimulation,direction,type) %>% 
  summarise(baseline = median(latency[leg == "pre"], na.rm = TRUE), # take average of 3 blocks, make new column
            tDCS = median(latency[leg == "tDCS"], na.rm = TRUE),
            post.1 = median(latency[leg == "post" & block <= 3], na.rm = TRUE),
            post.2 = median(latency[leg == "post" & block >= 4], na.rm = TRUE)) %>%
 gather(leg,latency,baseline,tDCS,post.1,post.2) %>% # gather new columns to use as factor
 mutate(leg = factor(leg, levels = c("baseline", "tDCS", "post.1", "post.2"))) # reorder factor levels

Line plot per leg, individual subjects

Now make the same plot, but for the data collapsed over 3 blocks. Also draw the plot for each individual subject, so we can see which subjects drive the baseline difference, and in which direction the stimulation effect goes for each subject (if there is any).

kanaiSubsPlot <- ggplot(latencyMedianLeg, aes(leg, latency, color = stimulation, shape = type)) +         
  facet_wrap(~subject, nrow = 5) +
  stat_summary(fun.y = mean, geom = "point", size = 2) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation))
kanaiSubsPlot

There are a couple of subjects that show large differences in the baseline already, especially S01.

Compute magnitude of baseline difference

Let’s look at the size of the baseline difference per subject.

baselineDiff <- latencyMedianLeg %>% 
  filter(leg == "baseline") %>% # keep only baseline data
  spread(stimulation, latency) %>% # make separate columns for anodal and cathodal
  mutate(latency.diff = anodal - cathodal) %>% # subtract the difference
  group_by(subject) %>% 
  summarise(latency.diff = mean(latency.diff))# keep the average difference per subject
kable(baselineDiff, caption = 'Difference between baseline saccade latencies in anodal and cathodal session')
subject latency.diff
S01 39.125
S02 18.625
S03 2.375
S04 -6.125
S05 -17.500
S06 -3.875
S07 5.625
S08 11.125
S09 23.750
S10 14.750
S11 1.000
S12 8.375
S13 4.000
S14 -10.375
S15 1.875
S16 -18.750
S17 -5.500
S18 -2.875
S19 1.000
S20 4.750

There are a few subjects with substantial latency differences between sessions; the three largest of which are all slower in the anodal session (positive values). The mean difference is 3.6 ms.

Exclude S01 and S16

It seems reasonable to exclude subject 1 from further analysis, because of three things:

  • S01 shows the largest baseline difference between the anodal and cathodal sessions.
  • Overall, S01 is much slower than all other subjects, by several tens of milliseconds.
  • The first session for S01 was aborted because S01 was not feeling well. It was repeated at a later date, so S01 came to the lab 3 times in total instead of two.

However, S01 also seems to show the largest effect of stimulation, for both anodal and cathodal stimulation. It is even in the expected direction: faster saccades than baseline in the anodal session, slower in cathodal.

S16’s data quality was poor in the first session and also shows a large baseline difference

latencyMedianLegExcl <- filter(latencyMedianLeg, subject != "S01") # discard rows from S01
latencyMedianLegExcl$subject <- factor(latencyMedianLegExcl$subject) #remake factor as it now has one level less

Line plot per leg over all subjects

Now that we’ve excluded subject(s) and collapsed data over blocks, let’s look at the group average plot for the first time.

kanaiPlot <- ggplot(latencyMedianLegExcl, aes(leg, latency, color = stimulation, shape = stimulation)) +         
  facet_grid(type ~ direction) +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
kanaiPlot

Even without S01, there is still a small baseline difference of 1.7 ms. There also seems to be a tiny effect in the center-left saccade condition that’s in the expected direction for both stimulation sessions, but it’s about the size of the baseline difference.

Subtract baseline

The baseline difference is not informative and could obscure real changes from baseline within subjects. Therefore, subtract the baseline from each subsequent measurement.

latencyMedianBaseline <- latencyMedianLegExcl %>%
  group_by(subject,stimulation,direction,type) %>% # for each condition, subtract baseline scores and make new columns
  summarise(tDCS = latency[leg == "tDCS"] - latency[leg == "baseline"], 
           post.1 = latency[leg == "post.1"] - latency[leg == "baseline"],
           post.2 = latency[leg == "post.2"] - latency[leg == "baseline"]) %>%
  gather(leg, latency, tDCS, post.1, post.2)  %>% # gather new columns to use as factor 
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) # reorder factor levels

Line plots per leg from baseline

kanaiPlotBase <- ggplot(latencyMedianBaseline, aes(leg, latency, color = stimulation, shape = stimulation)) +         
  facet_grid(type ~ direction) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3) +
  coord_cartesian(ylim = c(-15,15))
kanaiPlotBase

All changes from baseline are really tiny: 5 ms or less.

Individual subjects, anodal session

kanaiPlotBaseSubsAnodal <- ggplot(latencyMedianBaseline[latencyMedianBaseline$stimulation == "anodal", ], aes(leg, latency)) +
  facet_grid(type ~ direction) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_line(aes(group=subject,color=subject)) +
  stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
  stat_summary(fun.y = mean, geom = "point") +
  ggtitle("Anodal difference from baseline")
kanaiPlotBaseSubsAnodal

For the center saccades, most subjects follow the expected direction and are below the line. The left-lateral effect that is of primary interest is erratic though: only ~10 subjects are below the line, and none show an online-effect larger than 12 ms.

Individual subjects, cathodal session

kanaiPlotBaseSubsCathodal <- ggplot(latencyMedianBaseline[latencyMedianBaseline$stimulation == "cathodal", ], aes(leg, latency)) +
  facet_grid(type ~ direction) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_line(aes(group=subject,color=subject)) +
  stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
  stat_summary(fun.y = mean, geom = "point") + 
  ggtitle("Cathodal difference from baseline")
kanaiPlotBaseSubsCathodal

All of this is split pretty much 50-50, hence the average difference hovering around 0.

Statistics

T-tests for baseline differences

First, test for baseline differences for each combination of DIRECTION (left, right) and TYPE (center, lateral).

# keep only the baseline for left-lateral-saccades
latencyMedianPreLeftLateral <- latencyMedianLegExcl %>%
  filter(leg == "baseline", type == "lateral", direction == "left") %>%
  select(-leg,-type,-direction) %>%
  spread(stimulation, latency)
Adding missing grouping variables: `direction`
# keep only the baseline for right-lateral-saccades
latencyMedianPreRightLateral <- latencyMedianLegExcl %>%
  filter(leg == "baseline", type == "lateral", direction == "right") %>%
  select(-leg,-type,-direction) %>%
  spread(stimulation, latency)
Adding missing grouping variables: `direction`
# keep only the baseline for right-center-saccades
latencyMedianPreRightCenter <- latencyMedianLegExcl %>%
  filter(leg == "baseline", type == "center", direction == "right") %>%
  select(-leg,-type,-direction) %>%
  spread(stimulation, latency)
Adding missing grouping variables: `direction`
# keep only the baseline for left-center-saccades
latencyMedianPreLeftCenter <- latencyMedianLegExcl %>%
  filter(leg == "baseline", type == "center", direction == "left") %>%
  select(-leg,-type,-direction) %>%
  spread(stimulation, latency)
Adding missing grouping variables: `direction`
t.test(latencyMedianPreLeftLateral$anodal,latencyMedianPreLeftLateral$cathodal, paired = TRUE )

    Paired t-test

data:  latencyMedianPreLeftLateral$anodal and latencyMedianPreLeftLateral$cathodal
t = 0.59438, df = 18, p-value = 0.5597
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -3.668569  6.563306
sample estimates:
mean of the differences 
               1.447368 
t.test(latencyMedianPreRightLateral$anodal,latencyMedianPreRightLateral$cathodal, paired = TRUE )

    Paired t-test

data:  latencyMedianPreRightLateral$anodal and latencyMedianPreRightLateral$cathodal
t = 1.299, df = 18, p-value = 0.2104
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -2.290841  9.711893
sample estimates:
mean of the differences 
               3.710526 
t.test(latencyMedianPreLeftCenter$anodal,latencyMedianPreLeftCenter$cathodal, paired = TRUE )

    Paired t-test

data:  latencyMedianPreLeftCenter$anodal and latencyMedianPreLeftCenter$cathodal
t = 0.22858, df = 18, p-value = 0.8218
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -5.820180  7.241232
sample estimates:
mean of the differences 
              0.7105263 
t.test(latencyMedianPreRightCenter$anodal,latencyMedianPreRightCenter$cathodal, paired = TRUE )

    Paired t-test

data:  latencyMedianPreRightCenter$anodal and latencyMedianPreRightCenter$cathodal
t = 0.28503, df = 18, p-value = 0.7789
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -5.867854  7.709959
sample estimates:
mean of the differences 
              0.9210526 

None of the baseline differences are significant, so there is reason to leave the baseline data in the rest of the analyses.

Omnibus anova - saccade latency

Data: Outliers removed, collapesed into 15-minute intervals.

Dependent measure: saccadic latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (baseline, tDCS, post.1, post.2)
  • TYPE (lateral vs. center)
  • DIRECTION (left vs. right)
modelOmni <- ezANOVA(data = data.frame(latencyMedianLegExcl), # Repeated over subjects; type 3 sums of squares (cf. SPSS)
                        dv = .(latency), wid = .(subject), within = .(stimulation, leg, type, direction), type = 3)
kable(modelOmni$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 18 0.5448336 0.4699513 0.0026522
3 leg 3 54 0.5719557 0.6359004 0.0010567
4 type 1 18 26.5163705 0.0000673 * 0.2031419
5 direction 1 18 0.0443702 0.8355326 0.0003309
6 stimulation:leg 3 54 0.0276830 0.9937138 0.0000243
7 stimulation:type 1 18 0.7878197 0.3864669 0.0008186
8 leg:type 3 54 2.9395372 0.0412563 * 0.0015450
9 stimulation:direction 1 18 1.0471920 0.3197118 0.0004897
10 leg:direction 3 54 1.1003477 0.3570242 0.0002611
11 type:direction 1 18 1.3802333 0.2553696 0.0013139
12 stimulation:leg:type 3 54 0.0940556 0.9630059 0.0000290
13 stimulation:leg:direction 3 54 4.1363319 0.0103488 * 0.0007042
14 stimulation:type:direction 1 18 1.8347183 0.1923311 0.0001654
15 leg:type:direction 3 54 2.7550809 0.0512305 0.0006159
16 stimulation:leg:type:direction 3 54 0.9293330 0.4329215 0.0001384

Main effect: type

latencyMedianLegExcl %>%
  group_by(subject,type) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(type, latency)) +
  stat_summary(fun.data = mean_cl_normal, size = 1) +
  geom_jitter(width = 0.25)

This simply reflects that center saccades are faster than lateral saccades, because the location of the target is known.

Interaction: leg by type

latencyMedianLegExcl %>%
  group_by(subject,leg,type) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency, shape = type)) +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = type, linetype = type))

The effect of TYPE becomes larger over time: center saccades get faster, lateral saccades become slower.

Interaction: leg by type by direction

latencyMedianLegExcl %>%
  group_by(subject,leg,type,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency, shape = type)) +
  facet_wrap(~direction) +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = type, linetype = type))

This interaction of LEG and TYPE appears to occur to a lesser extent for left saccades. The “tDCS” block is the deviant here, but there is no interaction with stimulation.

ANOVA matching Kanai et al. (2012) - saccade latency

Differing from the previous omnibus analysis, Kanai et al. (2012) analysed shifts from baseline and only had lateral saccades.

Data:

  • Outliers removed
  • Collapsed into 15-minute intervals
  • Subtract the baseline from each subsequent block
  • Discard center, keep only lateral saccades

Dependent measure: saccadic latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)
latencyMedianBaselineLateral <- filter(latencyMedianBaseline, type == "lateral") # keep only lateral saccades
modelKanai <- ezANOVA(data = data.frame(latencyMedianBaselineLateral),
                        dv = .(latency), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
# OR, without the EZ package:
# modelKanai=aov(latency~stimulation*leg*direction + Error(subject/(stimulation*leg*direction)),data=latencyMedianBaselineLateral)
# summary(modelKanai)
kable(modelKanai$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 18 0.1056396 0.7489113 0.0011603
3 leg 2 36 3.0852605 0.0579807 0.0254120
4 direction 1 18 0.0006761 0.9795419 0.0000049
5 stimulation:leg 2 36 0.0500856 0.9512141 0.0001864
6 stimulation:direction 1 18 0.1124817 0.7412135 0.0002421
7 leg:direction 2 36 1.6749929 0.2015777 0.0014317
8 stimulation:leg:direction 2 36 4.0522338 0.0258677 * 0.0060139

Main effect of direction

latencyMedianBaselineLateral %>%
  group_by(subject,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(direction, latency)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.data = mean_cl_normal, size = 1) +
  geom_jitter(width = 0.25)

Right saccades become slower with respect to the baseline; left saccades do not. However, the effect is tiny (1-2 ms) and there is no interaction with STIMULATION.

ANOVA matching Kanai et al. (2012) - center saccades

Repeat the same ANOVA, but now for center saccades (which Kanai did not have).

latencyMedianBaselineCenter <- filter(latencyMedianBaseline, type == "center") # keep only lateral saccades
modelKanaiCenter <- ezANOVA(data = data.frame(latencyMedianBaselineCenter),
                        dv = .(latency), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
# OR, without the EZ package:
# modelKanai=aov(latency~stimulation*leg*direction + Error(subject/(stimulation*leg*direction)),data=latencyMedianBaselineLateral)
# summary(modelKanai)
kable(modelKanaiCenter$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 18 0.0125981 0.9118744 0.0001639
3 leg 2 36 0.7986263 0.4577571 0.0027491
4 direction 1 18 4.2193901 0.0547812 0.0127626
5 stimulation:leg 2 36 0.0519098 0.9494854 0.0001221
6 stimulation:direction 1 18 0.0980885 0.7577357 0.0001511
7 leg:direction 2 36 1.8879711 0.1660644 0.0025036
8 stimulation:leg:direction 2 36 3.2728364 0.0494365 * 0.0032078

ANOVA without subtracting baseline, for lateral saccades - saccade latency

Kanai et al. analyzed the baseline-subtracted data; now repeat the same ANOVA with the baseline block still present.

Data:

  • Outliers removed
  • Collapsed into 15-minute intervals
  • Discard center, keep only lateral saccades

Dependent measure: saccadic latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)
# keep only lateral saccades
latencyMedianLateral <- latencyMedianLegExcl %>%
  filter(type == "lateral") %>%
  select(-type)
modelLateral <- ezANOVA(data = data.frame(latencyMedianLateral),
                        dv = .(latency), wid = .(subject), within = .(stimulation, leg, direction), type = 3)
kable(modelLateral$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 18 1.1896030 0.2897954 0.0057760
3 leg 3 54 2.1450309 0.1052250 0.0034252
4 direction 1 18 0.3432586 0.5652290 0.0026728
5 stimulation:leg 3 54 0.0736893 0.9738537 0.0000562
6 stimulation:direction 1 18 1.7519802 0.2021940 0.0011053
7 leg:direction 3 54 0.5348350 0.6603829 0.0001691
8 stimulation:leg:direction 3 54 3.0084971 0.0380553 * 0.0007197

Leg by direction interaction

latencyMedianLateral %>%
  group_by(subject,leg,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency, shape = direction)) +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = direction, linetype = direction))

Pretty erratic pattern, and no interaction with STIMULATION either.

ANOVA without subtracting baseline, for center saccades - saccade latency

Same as previous, but now for center saccades.

latencyMedianCenter <- latencyMedianLegExcl %>%
  filter(type == "center") %>%
  select(-type)
modelCenter <- ezANOVA(data = data.frame(latencyMedianCenter),
                        dv = .(latency), wid = .(subject), within = .(
                          stimulation, leg, direction), type = 3)
kable(modelCenter$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 18 0.0818013 0.7781366 0.0005891
3 leg 3 54 0.4720792 0.7030047 0.0015717
4 direction 1 18 0.0399289 0.8438598 0.0003658
5 stimulation:leg 3 54 0.0290943 0.9932360 0.0000499
6 stimulation:direction 1 18 0.2061376 0.6552385 0.0000962
7 leg:direction 3 54 2.7402193 0.0521336 0.0017524
8 stimulation:leg:direction 3 54 2.3794025 0.0797697 0.0009944

Bayesian linear mixed effects matching Kanai - saccade latency

Test against the null model

bfKanaiNull = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(latencyMedianBaselineLateral), whichModels="withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiNull = sort(bfKanaiNull, decreasing = TRUE) # sort such that winning model is at the top

First we compare all models to the most simple (null) model, which is the intercept only + random effect model: latency ~ subject. This does not test for effects of SUBJECT but models it as a nuisance factor (whichRandom = "subject"). In addition, to decrease the model space, we do not consider models that have an interaction without the corresponding main effects (whichModels = "withmain").

kable(select(extractBF(bfKanaiNull), bf)) # show only the Bayes factors in a table
bf
leg + subject 1.9394726
stimulation + leg + subject 0.3327031
direction + leg + subject 0.2801473
stimulation + subject 0.1716592
direction + subject 0.1427363
stimulation + direction + leg + subject 0.0479931
stimulation + leg + stimulation:leg + subject 0.0279650
direction + leg + direction:leg + subject 0.0273854
stimulation + direction + subject 0.0243691
stimulation + direction + stimulation:direction + leg + subject 0.0095508
stimulation + direction + stimulation:direction + subject 0.0052792
stimulation + direction + leg + direction:leg + subject 0.0047485
stimulation + direction + leg + stimulation:leg + subject 0.0039681
stimulation + direction + stimulation:direction + leg + direction:leg + subject 0.0009712
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 0.0008092
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.0003951
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.0000795
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0000229

The winning model is the one with all main effects, with a Bayes factor of 1.9. We can compute the evidence for a particular effect by comparing this winning model with the best-fitting model that does not contain the effect. We can compute the evidence for absence of a particular effect by comparing the winning model with the best-fitting model that does contain the effect.

  • STIMULATION. This effect can be quantified by comparing the Bayes factors of the first and the 3rd model : 6.9. This constitues moderate evidence for the presence of a stimulation effect.
  • DIRECTION. This effect can be quantified by comparing the first and the 2nd model : 5.8. This constitues anecdotal evidence for the presence of a direction effect.

  • Interaction of STIMULATION and DIRECTION. This term is not in the winning model, and first shows up in the fourth model. The Bayes factor for the comparison of both models is 11.3. This constitues moderate evidence for the absence of an interaction between stimulation and direction.
  • Interaction of STIMULATION, and LEG. Bayes factor: 70.8. This constitutes moderate evidence for the absence of an interaction between stimulation and leg.
  • Three-way interaction. Bayes factor: 8.4607710^{4}. This constitutes strong evidence for the absence of an interaction between stimulation, leg and direction.

Test against the full model

Another option for quantifying evidence for a particular effect is to compare the full model to a model where that effect is omitted (whichModels = top"). The full model is stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject.

bfKanaiFull = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(latencyMedianBaselineLateral), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiFull
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg + subject , BF is...
[1] Omit direction:leg:stimulation : 3.531213  <U+00B1>2.8%
[2] Omit direction:leg             : 9.958357  <U+00B1>2.39%
[3] Omit leg:stimulation           : 12.17389  <U+00B1>2.93%
[4] Omit direction:stimulation     : 5.00078   <U+00B1>2.83%
[5] Omit leg                       : 0.5059081 <U+00B1>2.83%
[6] Omit direction                 : 7.274857  <U+00B1>2.61%
[7] Omit stimulation               : 5.96352   <U+00B1>3.1%

Against denominator:
  latency ~ stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg +     subject 
---
Bayes factor type: BFlinearModel, JZS

Removing the DIRECTION effect from the model yields a lower Bayes Factor, so including this effect improved the model. This thus constitues (some) evidence for the alternative: 1 \ 7.275 = 0.1. The evidence for a stimulation effect is also about the same: 0.2.

On the contrary, removing the interactions actually improves the model, so there is moderate evidence for the absence of interaction effects.

All in all, for most effects, the result is qualitatively similar to the approach of testing against the null-model. Only the evidence for absence of the three-way interaction is much, much smaller here.

Bayesian linear mixed effects matching Kanai - center saccades

bfKanaiCenter = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(latencyMedianBaselineCenter), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiCenter
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg + subject , BF is...
[1] Omit direction:leg:stimulation : 4.287449 <U+00B1>3.81%
[2] Omit direction:leg             : 7.782446 <U+00B1>2.85%
[3] Omit leg:stimulation           : 12.15958 <U+00B1>3.32%
[4] Omit direction:stimulation     : 5.243033 <U+00B1>4.65%
[5] Omit leg                       : 18.55041 <U+00B1>33.29%
[6] Omit direction                 : 1.008738 <U+00B1>46.93%
[7] Omit stimulation               : 6.57132  <U+00B1>2.11%

Against denominator:
  latency ~ stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg +     subject 
---
Bayes factor type: BFlinearModel, JZS

Bayesian linear mixed effects with baseline - saccade latency

Repeat the analysis when the baseline is not subtracted, and also for center saccades.

Lateral saccades

# keep only lateral saccades
latencyMedianLateral <- latencyMedianLegExcl %>%
  filter(type == "lateral") %>%
  select(-type)
  
bfLateral = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(latencyMedianLateral), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfLateral
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg + subject , BF is...
[1] Omit direction:leg:stimulation : 11.40207  <U+00B1>2.12%
[2] Omit direction:leg             : 28.10296  <U+00B1>1.9%
[3] Omit leg:stimulation           : 28.90428  <U+00B1>1.76%
[4] Omit direction:stimulation     : 3.637222  <U+00B1>1.88%
[5] Omit leg                       : 17.51425  <U+00B1>3.04%
[6] Omit direction                 : 2.407894  <U+00B1>1.74%
[7] Omit stimulation               : 0.5932669 <U+00B1>3.19%

Against denominator:
  latency ~ stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg +     subject 
---
Bayes factor type: BFlinearModel, JZS

When including the baseline, the evidence for null effects are stronger all around.

Center saccades

# keep only center saccades
latencyMedianCenter <- latencyMedianLegExcl %>%
  filter(type == "center") %>%
  select(-type)
  
bfCenter = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(latencyMedianCenter), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfCenter
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg + subject , BF is...
[1] Omit direction:leg:stimulation : 11.78923 <U+00B1>4.91%
[2] Omit direction:leg             : 19.688   <U+00B1>5.21%
[3] Omit leg:stimulation           : 31.49381 <U+00B1>7.63%
[4] Omit direction:stimulation     : 5.853747 <U+00B1>2.62%
[5] Omit leg                       : 44.50356 <U+00B1>2.83%
[6] Omit direction                 : 7.08912  <U+00B1>1.9%
[7] Omit stimulation               : 6.663299 <U+00B1>1.74%

Against denominator:
  latency ~ stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg +     subject 
---
Bayes factor type: BFlinearModel, JZS

Now the model improves all the time, no matter which effect is omitted.

Reaction time distributions

Split data in equal blocks

We want the same number of trials to go into each distribution, so we’ll split the 30-minute long post leg into two. Then we have 4 15-minute long data segments: pre, tDCS, post.1 and post.2.

# Group single-trial data in 4 legs instead of 3
groupDataBlocked <- groupData %>%
  mutate(leg = as.character(leg)) %>% #un-factor the leg column so we can change it
  mutate(leg=replace(leg, leg == "post", "post.1"), # split the "post" level into two
         leg=replace(leg, block > 3, "post.2")) %>%
  mutate(leg = factor(leg, levels = c("pre","tDCS","post.1","post.2"))) #re-factor

Fit the model

Next we fit an ex-gaussian distribution using the retimes package. One model is fit for each combination of:

  • SUBJECT (S01, S02, etc.)
  • STIMULATION (anodal, cathodal)
  • LEG (pre, tDCS, post.1, post.2)
  • TYPE (center, lateral)
  • DIRECTION (left, right)

The ex-gaussian distribution is the convolution of a normal and an exponential distribution. It can be characterized with 3 parameters:

  • \(\mu\) (mu): the mean of the normal distribution
  • \(\sigma\) (sigma): the variance of the normal distribution
  • \(\tau\) (tau): the rate parameter of the exponential distribution

We’ll do minimal pre-processing: keep all subjects, only discard negative RTs

groupDataFit <- groupDataBlocked %>%
  filter(latency > 0) %>% # throw out missing and negative RTs
  group_by(subject,stimulation,leg,type,direction) %>% # for every condition
  summarise(result = list(data.frame(t(attr(timefit(latency),"par"))))) %>% # [see below]
  ungroup() %>% # remove grouping information (otherwise unnest will not work)
  unnest() # unpack the list column, so each parameter gets its own column
  
# 1. fit the ex-gaussian to the latency data with the timefit() function
# 2. extract the fitted parameters from the resulting object with "attr()"
# 3. transpose ("t()") so every parameter is in a different column
# 4. convert to a data frame with one column per parameter
# 5. pack in a list so we have something of size 1 we can assign to the dataframe
# "result" is now a list-column, where each element is a dataframe with estimates of the 3 parameters
# Alternatively, create a function to fit the data, and then call it through dplyr::do
#myFunc <- function(x){
#  data.frame(t(attr(timefit(x),"par")))
#}
#groupDataFit <- groupDataBlocked %>%
#  group_by(subject,stimulation,leg,type,direction) %>% # for every condition
#  do((myFunc(.$latency)))

Inspect fitted parameters

ggplot(groupDataFit, aes(interaction(leg,stimulation), mu, color = subject)) +
  facet_grid(type~direction) + 
  stat_summary(fun.y = mean, fun.ymin = function(x) mean(x) - 2*sd(x), fun.ymax = function(x) mean(x) + 2*sd(x), aes(group = 1)) + # plot mean and 2*SD to watch for outliers; we need group = 1 because the x-axis is a combination of factors
  geom_jitter(width = 0.6) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

For center saccades some estimates of \(\mu\) are simply too fast (e.g. S09); they reflect premature eye movements. The distribution is also not a good fit in these cases.

For center saccades, it looks reasonable. S01 is more than 2 SD away from the mean, but the fit is excellent.

ggplot(groupDataFit, aes(interaction(leg,stimulation), sigma, color = subject)) +
  facet_grid(type~direction) +
  stat_summary(fun.y = mean, fun.ymin = function(x) mean(x) - 2*sd(x), fun.ymax = function(x) mean(x) + 2*sd(x), aes(group = 1)) +
  geom_jitter(width = 0.6) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

Center saccades appear to have larger \(\sigma\) than lateral. But if you inspect the distributions, the peak is actually much sharper, which should indicate lower variance. The problem is that the shape of many distributions does not conform well: many saccades are early and have little variance, but then there’s also a bump in the right-tail which causes the sigma-parameter to increase.

Values for the lateral distribution seem reasonable. 2 estimates of \(\sigma\) are too close to zero, others are too high, but the spread is not unreasonable. Inspecting these distributions also reveals presence of a “shoulder” right of the peak, which can either spread the distribution out or narrow it too much.

ggplot(groupDataFit, aes(interaction(leg,stimulation), tau, color = subject)) +
  facet_grid(type~direction) +
  stat_summary(fun.y = mean, fun.ymin = function(x) mean(x) - 2*sd(x), fun.ymax = function(x) mean(x) + 2*sd(x), aes(group = 1)) +
  geom_jitter(width = 0.6) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

Particularly for center saccades, \(\tau\) is many times estimated at 0. This means that the distribution is actually just a normal distribution. For center saccades that makes sense, as \(\tau\) is responsible for the longer right tail that characterizes the ex-gaussian distribution. When saccades are all super fast, this tail is not present.

Mu

Plot

muLinePlot <- ggplot(groupDataFit, aes(leg, mu, color = stimulation, shape = stimulation)) +         
  facet_grid(type ~ direction) +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
muLinePlot

Statistics

Lateral

muLateral <- groupDataFit %>%
  filter(type == "lateral") %>%
  select(-type)
modelMuLateral <- ezANOVA(data = data.frame(muLateral), dv = .(mu), wid = .(subject), within = .(stimulation, leg, direction), type = 3)
kable(modelMuLateral$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 19 0.4962574 0.4896947 0.0018185
3 leg 3 57 4.0770965 0.0108122 * 0.0068828
4 direction 1 19 0.0862917 0.7721303 0.0007264
5 stimulation:leg 3 57 0.2632381 0.8515909 0.0003878
6 stimulation:direction 1 19 2.4797673 0.1318238 0.0016080
7 leg:direction 3 57 3.7885316 0.0150864 * 0.0027886
8 stimulation:leg:direction 3 57 1.1099797 0.3526354 0.0010857
bfMuLateral = anovaBF(mu~stimulation*leg*direction+subject, data = data.frame(muLateral), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfMuLateral
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject , BF is...
[1] Omit direction:leg:stimulation : 10.44442 <U+00B1>5.83%
[2] Omit direction:leg             : 11.20198 <U+00B1>5.71%
[3] Omit direction:stimulation     : 2.92745  <U+00B1>5.11%
[4] Omit leg:stimulation           : 24.46828 <U+00B1>4.89%
[5] Omit direction                 : 5.742728 <U+00B1>5.39%
[6] Omit leg                       : 4.756499 <U+00B1>5.04%
[7] Omit stimulation               : 3.504989 <U+00B1>4.89%

Against denominator:
  mu ~ stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject 
---
Bayes factor type: BFlinearModel, JZS

Center

muCenter <- groupDataFit %>%
  filter(type == "center") %>%
  select(-type)
modelMuCenter <- ezANOVA(data = data.frame(muCenter), dv = .(mu), wid = .(subject), within = .(stimulation, leg, direction), type = 3)
kable(modelMuCenter$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 19 0.0001866 0.9892442 0.0000011
3 leg 3 57 1.0722467 0.3681380 0.0060317
4 direction 1 19 0.0003526 0.9852143 0.0000024
5 stimulation:leg 3 57 1.2683962 0.2938734 0.0043846
6 stimulation:direction 1 19 0.6514095 0.4295975 0.0010113
7 leg:direction 3 57 0.5453032 0.6533091 0.0020456
8 stimulation:leg:direction 3 57 0.6311947 0.5978988 0.0014300
bfMuCenter = anovaBF(mu~stimulation*leg*direction+subject, data = data.frame(muCenter), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfMuCenter
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject , BF is...
[1] Omit direction:leg:stimulation : 11.44415 <U+00B1>3.15%
[2] Omit direction:leg             : 19.57465 <U+00B1>2.23%
[3] Omit direction:stimulation     : 4.617263 <U+00B1>2.46%
[4] Omit leg:stimulation           : 12.14351 <U+00B1>2.29%
[5] Omit direction                 : 8.223817 <U+00B1>3.08%
[6] Omit leg                       : 17.60705 <U+00B1>2.35%
[7] Omit stimulation               : 8.096295 <U+00B1>2.49%

Against denominator:
  mu ~ stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject 
---
Bayes factor type: BFlinearModel, JZS

Sigma

Plot

sigmaLinePlot <- ggplot(groupDataFit, aes(leg, sigma, color = stimulation, shape = stimulation)) +         
  facet_grid(type ~ direction) +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
sigmaLinePlot

Statistics

Lateral

sigmaLateral <- groupDataFit %>%
  filter(type == "lateral") %>%
  select(-type)
modelSigmaLateral <- ezANOVA(data = data.frame(sigmaLateral), dv = .(sigma), wid = .(subject), within = .(stimulation, leg, direction), type = 3)
kable(modelSigmaLateral$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 19 0.3070893 0.5859358 0.0020213
3 leg 3 57 4.8020840 0.0047376 * 0.0205278
4 direction 1 19 0.4964608 0.4896068 0.0019499
5 stimulation:leg 3 57 0.3144879 0.8148281 0.0015190
6 stimulation:direction 1 19 0.8417414 0.3703991 0.0012920
7 leg:direction 3 57 1.4989067 0.2245956 0.0037770
8 stimulation:leg:direction 3 57 1.5867054 0.2025735 0.0049500
bfSigmaLateral = anovaBF(sigma~stimulation*leg*direction+subject, data = data.frame(sigmaLateral), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfSigmaLateral
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject , BF is...
[1] Omit direction:leg:stimulation : 5.269379  <U+00B1>2.38%
[2] Omit direction:leg             : 13.71165  <U+00B1>5.71%
[3] Omit direction:stimulation     : 4.112387  <U+00B1>2.31%
[4] Omit leg:stimulation           : 24.85324  <U+00B1>11%
[5] Omit direction                 : 4.874215  <U+00B1>2.83%
[6] Omit leg                       : 0.4419473 <U+00B1>10.42%
[7] Omit stimulation               : 4.648076  <U+00B1>3.3%

Against denominator:
  sigma ~ stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject 
---
Bayes factor type: BFlinearModel, JZS

Center

sigmaCenter <- groupDataFit %>%
  filter(type == "center") %>%
  select(-type)
modelSigmaCenter <- ezANOVA(data = data.frame(sigmaCenter), dv = .(sigma), wid = .(subject), within = .(stimulation, leg, direction), type = 3)
kable(modelSigmaCenter$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 19 0.6283303 0.4377549 0.0037630
3 leg 3 57 5.2100287 0.0030012 * 0.0195091
4 direction 1 19 3.1389212 0.0924826 0.0211137
5 stimulation:leg 3 57 0.5290551 0.6641446 0.0026847
6 stimulation:direction 1 19 0.0135394 0.9085893 0.0000365
7 leg:direction 3 57 0.6716000 0.5729879 0.0032568
8 stimulation:leg:direction 3 57 0.7492325 0.5273056 0.0019792
bfSigmaCenter = anovaBF(sigma~stimulation*leg*direction+subject, data = data.frame(sigmaCenter), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfSigmaCenter
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject , BF is...
[1] Omit direction:leg:stimulation : 10.06561   <U+00B1>3.98%
[2] Omit direction:leg             : 15.74758   <U+00B1>3.55%
[3] Omit direction:stimulation     : 5.793119   <U+00B1>3.68%
[4] Omit leg:stimulation           : 17.38659   <U+00B1>3.72%
[5] Omit direction                 : 0.05443641 <U+00B1>3.56%
[6] Omit leg                       : 1.08491    <U+00B1>3.98%
[7] Omit stimulation               : 3.826635   <U+00B1>10.66%

Against denominator:
  sigma ~ stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject 
---
Bayes factor type: BFlinearModel, JZS

Tau

Plot

tauLinePlot <- ggplot(groupDataFit, aes(leg, tau, color = stimulation, shape = stimulation)) +         
  facet_grid(type ~ direction) +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
tauLinePlot

Statistics

Lateral

tauLateral <- groupDataFit %>%
  filter(type == "lateral") %>%
  select(-type)
modelTauLateral <- ezANOVA(data = data.frame(tauLateral), dv = .(tau), wid = .(subject), within = .(stimulation, leg, direction), type = 3)
kable(modelTauLateral$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 19 2.4821341 0.1316505 0.0108311
3 leg 3 57 2.7975288 0.0481938 * 0.0178416
4 direction 1 19 0.0020449 0.9644036 0.0000099
5 stimulation:leg 3 57 0.5265115 0.6658504 0.0018047
6 stimulation:direction 1 19 0.0180463 0.8945494 0.0000357
7 leg:direction 3 57 2.0908871 0.1114990 0.0045650
8 stimulation:leg:direction 3 57 0.3432422 0.7941361 0.0011038
bfTauLateral = anovaBF(tau~stimulation*leg*direction+subject, data = data.frame(tauLateral), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfTauLateral
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject , BF is...
[1] Omit direction:leg:stimulation : 11.00158  <U+00B1>5.51%
[2] Omit direction:leg             : 10.05369  <U+00B1>5.53%
[3] Omit direction:stimulation     : 5.436445  <U+00B1>5.41%
[4] Omit leg:stimulation           : 31.78977  <U+00B1>37.27%
[5] Omit direction                 : 7.690549  <U+00B1>5.6%
[6] Omit leg                       : 0.6883419 <U+00B1>5.7%
[7] Omit stimulation               : 0.3571577 <U+00B1>5.46%

Against denominator:
  tau ~ stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject 
---
Bayes factor type: BFlinearModel, JZS

Center

tauCenter <- groupDataFit %>%
  filter(type == "center") %>%
  select(-type)
modelTauCenter <- ezANOVA(data = data.frame(tauCenter), dv = .(tau), wid = .(subject), within = .(stimulation, leg, direction), type = 3)
kable(modelTauCenter$ANOVA)
Effect DFn DFd F p p<.05 ges
2 stimulation 1 19 0.9421655 0.3439170 0.0049757
3 leg 3 57 0.9034300 0.4452132 0.0068505
4 direction 1 19 0.4129620 0.5281491 0.0016242
5 stimulation:leg 3 57 2.3352550 0.0833949 0.0095634
6 stimulation:direction 1 19 0.6623347 0.4258193 0.0014819
7 leg:direction 3 57 1.1465225 0.3381913 0.0067472
8 stimulation:leg:direction 3 57 0.1164547 0.9501026 0.0004604
bfTauCenter = anovaBF(tau~stimulation*leg*direction+subject, data = data.frame(tauCenter), whichModels="top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfTauCenter
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject , BF is...
[1] Omit direction:leg:stimulation : 13.92171 <U+00B1>3.97%
[2] Omit direction:leg             : 8.539389 <U+00B1>3.44%
[3] Omit direction:stimulation     : 4.293162 <U+00B1>3.61%
[4] Omit leg:stimulation           : 5.506957 <U+00B1>5.76%
[5] Omit direction                 : 5.55446  <U+00B1>3.29%
[6] Omit leg                       : 18.09544 <U+00B1>3.77%
[7] Omit stimulation               : 2.643075 <U+00B1>3.74%

Against denominator:
  tau ~ stimulation + leg + direction + stimulation:leg + stimulation:direction + leg:direction + stimulation:leg:direction + subject 
---
Bayes factor type: BFlinearModel, JZS
LS0tCnRpdGxlOiAiVHJhbnNjcmFuaWFsIGRpcmVjdCBjdXJyZW50IHN0aW11bGF0aW9uIG9mIHRoZSByaWdodCBmcm9udGFsIGV5ZSBmaWVsZCBpbiBhIHByb3NhY2NhZGUgdGFzayIKYXV0aG9yOiBMZW9uIFJldGVpZwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKYGBge3IgaW5jbHVkZT1GQUxTRX0KIyBEb24ndCBzaG93IHdhcm5pbmdzIGFuZCBtZXNzYWdlcyBpbiBIVE1MIG91dHB1dAprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmBgYAoKUiBub3RlYm9vayBmb3Igc3RhdGlzdGljYWwgYW5hbHlzaXMgb2YgdGhlIGBzYWNjLXREQ1NgIGRhdGFzZXQuIFByZXZpb3VzIHByb2Nlc3Npbmc6CgoqIFJhdyBkYXRhIHdlcmUgcGFyc2VkIGludG8gZXZlbnRzIChzYWNjYWRlcywgZml4YXRpb25zLCBldGMuKSBieSB0aGUgRXllTGluayBkYXRhIHdlcmUgY29sbGVjdGVkIG9uLgoqIEV2ZW50cyB3ZXJlIGV4dHJhY3RlZCBhbmQgc2FjY2FkZSBtZWFzdXJlcyB3ZXJlIGNvbXB1dGVkIHdpdGggYSBNQVRMQUIgc2NyaXB0LgoKYGBge3IgTG9hZCBzb21lIGxpYnJhcmllc30KIyBMb2FkIHNvbWUgbGlicmFyaWVzCmxpYnJhcnkoImRwbHlyIikgIyB3cmFuZ2xpbmcgZGF0YSBmcmFtZSBkYXRhCmxpYnJhcnkoInRpZHlyIikgIyB0aWR5aW5nIGRhdGEgZnJhbWVzCmxpYnJhcnkoImdncGxvdDIiKSAjIHBsb3R0aW5nCmxpYnJhcnkoImV6IikgIyBBTk9WQQpsaWJyYXJ5KCJrbml0ciIpICMgUiBtYXJrZG93biBvdXRwdXQgKGh0bWwsIHBkZiwgZXRjLikKbGlicmFyeSgiQmF5ZXNGYWN0b3IiKSAjIEJheWVzaWFuIHN0YXRpc3RpY3MKbGlicmFyeSgicmV0aW1lcyIpICMgRXgtR2F1c3NpYW4gcmVhY3Rpb24gdGltZSBkaXN0cmlidXRpb25zCmBgYAoKIyBRdWVzdGlvbm5haXJlcwoKIyMgUEFOQVMKCiMjIyBMb2FkIGRhdGEKCkluIGVhY2ggc2Vzc2lvbiBvZiB0aGUgZXhwZXJpbWVudCwgcGFydGljaXBhbnRzIGNvbXBsZXRlZCB0aGUgW1Bvc2l0aXZlIGFuZCBOZWdhdGl2ZSBBZmZlY3QgU2NhbGUgKFBBTkFTKV0oaHR0cDovL2Jvb2tzaXRlLmVsc2V2aWVyLmNvbS85NzgwMTIzNzQ1MTcwL0NoYXB0ZXIlMjAzL0NoYXB0ZXJfM19Xb3Jrc2hlZXRfMy4xLnBkZikgdHdpY2U6CgoxLiBfX1ByZS1tZWFzdXJlbWVudF9fOiBCZWZvcmUgc3RhcnRpbmcgc2V0dXAgb2YgdGhlIHREQ1MgYW5kIGV5ZSB0cmFja2VyCjIuIF9fUG9zdC1tZWFzdXJlbWVudF9fOiBBZnRlciB0aGUgZWxlY3Ryb2RlcyB3ZXJlIHJlbW92ZWQgZm9sbG93aW5nIHRhc2sgY29tcGxldGlvbgoKQXMgbW9zdCBwYXJ0aWNpcGFudHMgd2VyZSBuYXRpdmUgRHV0Y2ggc3BlYWtlcnMsIHdlIGFsc28gdXNlZCBhIFtEdXRjaCBsYW5ndWFnZSB2ZXJzaW9uXShodHRwOi8vd3d3LmVrZ3AudWdlbnQuYmUvcGFnZXMvbmwvdnJhZ2VubGlqc3Rlbi9QQU5BUy5wZGYpIG9mIHRoZSBQQU5BUywgYXMgcmVwb3J0ZWQgYnkgW0VuZ2VsZW4gZXQgYWwuICgyMDA2KV0oaHR0cDovL2xpbmsuc3ByaW5nZXIuY29tL2FydGljbGUvMTAuMTAwNy9CRjAzMDg3OTc5KS4KCmBgYHtyIExvYWQgUEFOQVMgZGF0YX0KIyBMb2FkIHRoZSBkYXRhIGZyYW1lCmRhdGFGaWxlIDwtIGZpbGUucGF0aCgiZGF0YSIsICJQQU5BUy5jc3YiKQpwYW5hc0RhdGEgPC0gcmVhZC5jc3YoZGF0YUZpbGUsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICI7IikKCnBhbmFzRGF0YSR0aW1lIDwtIGZhY3RvcihwYW5hc0RhdGEkdGltZSwgbGV2ZWxzID0gYygicHJlIiwicG9zdCIpKSAjIHJlb3JkZXIgbGV2ZWxzIGNocm9ub2xvZ2ljYWxseSBpbnN0ZWFkIG9mIGFscGhhYmV0aWNhbGx5CmhlYWQocGFuYXNEYXRhKSAjIHNob3cgZGF0YSBmcmFtZQpgYGAKCl9fRmFjdG9yc19fOgoKKiBfc3ViamVjdF86IHN1YmplY3QgSUQgKGBTMDFgLCBgUzAyYCwgZXRjKQoqIF9zZXNzaW9uXzogV2hldGhlciBkYXRhIGFyZSBmcm9tIHRoZSBgZmlyc3RgIG9yIGBzZWNvbmRgIHNlc3Npb24KKiBfc3RpbXVsYXRpb25fOiBXaGV0aGVyIGRhdGEgYXJlIGZyb20gdGhlIGBhbm9kYWxgIG9yIGBjYXRob2RhbGAgc2Vzc2lvbgoqIF90aW1lXzogV2hldGhlciBkYXRhIGFyZSBmcm9tIHRoZSBgcHJlYCBvciBgcG9zdGAgbWVhc3VyZW1lbnQKCl9fREFUQV9fOgoKVGhlIFBBTkFTIGNvbnRhaW5zIDIwIGl0ZW1zLCBzcGxpdCBlcXVhbGx5IGludG8gcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGFmZmVjdC4gRWFjaCBpdGVtIGlzIHJhdGVkIG9uIGEgTGlrZXJ0IHNjYWxlOgoKMS4gdmVyeSBzbGlnaHRseSBvciBub3QgYXQgYWxsCjIuIGEgbGl0dGxlCjMuIG1vZGVyYXRlbHkKNC4gcXVpdGUgYSBiaXQKNS4gZXh0cmVtZWx5CgpUbyBvYnRhaW4gYSBwb3NpdGl2ZSBhZmZlY3Qgc2NvcmUsIHdlIHN1bSBpdGVtczogMSAoaW50ZXJlc3RlZCksIDMgKGV4Y2l0ZWQpLCA1IChzdHJvbmcpLCA5IChlbnRodXNpYXN0aWMpLCAxMCAocHJvdWQpLCAxMiAoYWxlcnQpLCAxNCAoaW5zcGlyZWQpLCAxNiAoZGV0ZXJtaW5lZCksIDE3IChhdHRlbnRpdmUpIGFuZCAxOSAoYWN0aXZlKS4KClRvIG9idGFpbiBhIG5lZ2F0aXZlIGFmZmVjdCBzY29yZSwgd2Ugc3VtIGl0ZW1zOiAyIChkaXN0cmVzc2VkKSwgNCAodXBzZXQpLCA2IChndWlsdHkpLCA3IChzY2FyZWQpLCA4IChob3N0aWxlKSwgMTEgKGlycml0YWJsZSksIDEzIChhc2hhbWVkKSwgMTUgKG5lcnZvdXMpLCAxOCAoaml0dGVyeSkgYW5kIDIwIChhZnJhaWQpLgoKIyMjIFBvc3QtcHJlIGRpZmZlcmVuY2VzIHBlciBpdGVtCgpgYGB7ciBTdWJ0cmFjdCBwcmUgZnJvbSBwb3N0IGZvciBlYWNoIGl0ZW19CnBhbmFzUHJlUG9zdCA8LSBwYW5hc0RhdGEgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzZXNzaW9uLHN0aW11bGF0aW9uKSAlPiUgIyBmb3IgZWFjaCBzdWJqZWN0LCBzZXNzaW9uLCBzdGltdWxhdGlvbiBjb21iaW5hdGlvbgogIHNlbGVjdCgtdGltZSkgJT4lICMgZG9uJ3QgZG8gc3VidHJhY3Rpb24gZm9yIHRoaXMgY29sdW1uCiAgc3VtbWFyaXNlX2VhY2goZnVucyhkaWZmKC4pKSkgIyBzdWJ0cmFjdCBwcmUgYW5kIHBvc3QKYGBgCgpMZXQncyBwbG90IHRoZSBwb3N0LXByZSBkaWZmZXJlbmNlcyBmb3IgZWFjaCBpdGVtLCBzcGxpdCBmb3Igc3RpbXVsYXRpb24gc2Vzc2lvbi4KCmBgYHtyIFBsb3QgcG9zdC1wcmUgZGlmZmVyZW5jZXMgcGVyIGl0ZW19CnBhbmFzUHJlUG9zdCAlPiUKICBnYXRoZXIoaXRlbSwgc2NvcmUsIHBvcy4xLmludGVyZXN0ZWQ6bmVnLjIwLmFmcmFpZCkgJT4lICMgZ2F0aGVyIGFsbCBQQU5BUyBjb2x1bW5zIHNvIGl0IGNhbiBiZSB1c2VkIGFzIGEgZmFjdG9yCiAgZ2dwbG90KGFlcyhpdGVtLCBzY29yZSkpICsKICAgICAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjYpLCBhZXMoY29sb3IgPSBzdGltdWxhdGlvbikpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTEsMSkpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpCmBgYAoKTW9zdCBzY29yZXMgYmVjb21lIG5lZ2F0aXZlLCBtZWFuaW5nIHRoZSBgcG9zdGAgc2NvcmUgd2FzIHNtYWxsZXIgdGhhbiBgcHJlYC4gU28gdGhleSBnZW5lcmFsbHkgZmVlbCAibGVzcyIgb2YgZXZlcnl0aGluZy4gVGhpcyBzZWVtcyBwYXJ0aWN1bGFybHkgdGhlIGNhc2UgZm9yIHBvc2l0aXZlIGFmZmVjdCwgYWx0aG91Z2ggcGFydGljaXBhbnRzIGRvIGZlZWwgc2xpZ2h0bHkgbW9yZSBfcHJvdWRfLCBfZGV0ZXJtaW5lZF8sIGFuZCBfc3Ryb25nXy4KClRoZXkgYmVjb21lIHBhcnRpY3VsYXJseSBsZXNzIF9qaXR0ZXJ5XywgX25lcnZvdXNfLCBfaXJyaXRhYmxlXywgYW5kIGFsc28gbGVzcyBfYXR0ZW50aXZlXywgX2FjdGl2ZV8sIGFuZCBfZXhjaXRlZF8uCgpUaGUgYmlnZ2VzdCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBzZXNzaW9ucyBhcmUgaW4gdGhlIHBvc2l0aXZlIGl0ZW1zLCBleGNlcHQgZm9yIF9pcnJpdGFibGVfLgoKRm9yIHNvbWUgcG9zaXRpdmUgaXRlbXMsIGFub2RhbCBzdGltdWxhdGlvbiByZXN1bHRzIGluIGEgbW9yZSBwb3NpdGl2ZSBzY29yZSwgd2hpbGUgY2F0aG9kYWwgcmVlc3VsdHMgaW4gYSBtb3JlIG5lZ2F0aXZlIHNjb3JlOiBfYWxlcnRfLCBfaW5zcGlyZWRfLCBfZGV0ZXJtaW5lZF8sIGFuZCBfc3Ryb25nXy4KCiMjIyBDb21wb3NpdGUgcG9zaXRpdmUvbmVnYXRpdmUgc2NvcmVzCgpgYGB7ciBTdW0gdGhlIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSBpdGVtc30KcGFuYXNDb21wb3NpdGUgPC0gcGFuYXNEYXRhICU+JSAKICBtdXRhdGUocG9zaXRpdmUgPSByb3dTdW1zKHNlbGVjdCguLCBjb250YWlucygicG9zIikpKSkgJT4lICMgc3VtIGFsbCB0aGUgcG9zaXRpdmUgc2NvcmVzIHRvZ2V0aGVyCiAgbXV0YXRlKG5lZ2F0aXZlID0gcm93U3VtcyhzZWxlY3QoLiwgY29udGFpbnMoIm5lZyIpKSkpICU+JSAjIHN1bSBhbGwgdGhlIG5lZ2F0aXZlIHNjb3JlcyB0b2dldGhlcgogIHNlbGVjdChzdWJqZWN0OnRpbWUsIHBvc2l0aXZlLCBuZWdhdGl2ZSkgJT4lICMgZHJvcCB0aGUgb3JpZ2luYWwgUEFOQVMgY29sdW1ucwogIGdhdGhlcihhZmZlY3QsIHNjb3JlLCBwb3NpdGl2ZSwgbmVnYXRpdmUpICMgZ2F0aGVyIGFmZmVjdCBzbyBpdCBjYW4gYmUgdXNlZCBhcyBhIGZhY3RvcgpgYGAKCmBgYHtyIFBsb3QgdGhlIGNvbXBvc2l0ZSBzY29yZXN9CmdncGxvdChwYW5hc0NvbXBvc2l0ZSwgYWVzKHRpbWUsc2NvcmUsIGNvbG9yID0gc3RpbXVsYXRpb24pKSArCmZhY2V0X3dyYXAofmFmZmVjdCkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjUpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSkKYGBgCgpUaGUgbmVnYXRpdmUgc2NvcmVzIGFyZSBtdWNoIGxvd2VyIHRoYW4gdGhlIHBvc2l0aXZlIG92ZXJhbGwuCgpUaGUgcHJlIHRvIHBvc3QgZGlmZmVyZW5jZXMgYXJlIGxhcmdlciBmb3IgcG9zaXRpdmUgc2NvcmVzLCBwYXJ0aWN1bGFybHkgZm9yIHRoZSBjYXRob2RhbCBzZXNzaW9uLgoKIyMjIyBTdGF0aXN0aWNzOiBwb3NpdGl2ZSBzY29yZXMKClJlcGVhdGVkIG1lYXN1cmVzIEFOT1ZBIHdpdGggZmFjdG9ycyBTVElNVUxBVElPTiAoYW5vZGFsIHZzLiBjYXRob2RhbCkgYW5kIFRJTUUgKHByZSB2cy4gcG9zdCkKCmBgYHtyIFJNIEFOT1ZBIGZvciBQb3NpdGl2ZSBzY29yZXN9CnBhbmFzQ29tcG9zaXRlUG9zaXRpdmUgPC0gZmlsdGVyKHBhbmFzQ29tcG9zaXRlLCBhZmZlY3QgPT0gInBvc2l0aXZlIikgIyBuZXcgZGF0YSBmcmFtZSB3aXRoIG9ubHkgcG9zaXRpdmUgc2NvcmVzCgptb2RlbFBvc2l0aXZlIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUocGFuYXNDb21wb3NpdGVQb3NpdGl2ZSksICMgUmVwZWF0ZWQgb3ZlciBzdWJqZWN0czsgdHlwZSAzIHN1bXMgb2Ygc3F1YXJlcyAoY2YuIFNQU1MpCiAgICAgICAgICAgICAgICAgICAgICAgIGR2ID0gLihzY29yZSksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sIHRpbWUpLCB0eXBlID0gMykKa2FibGUobW9kZWxQb3NpdGl2ZSkKYGBgCgpTdWJqZWN0cycgbW9vZCBiZWNvbWVzIGxlc3MgcG9zaXRpdmUgYWZ0ZXIgc3RpbXVsYXRpb24sIHBhcnRpY3VsYXJseSBpbiB0aGUgY2F0aG9kYWwgc2Vzc2lvbgoKIyMjIyBTdGF0aXN0aWNzOiBuZWdhdGl2ZSBzY29yZXMKClJlcGVhdGVkIG1lYXN1cmVzIEFOT1ZBIHdpdGggZmFjdG9ycyBTVElNVUxBVElPTiAoYW5vZGFsIHZzLiBjYXRob2RhbCkgYW5kIFRJTUUgKHByZSB2cy4gcG9zdCkKCmBgYHtyIFJNIEFOT1ZBIGZvciBuZWdhdGl2ZSBzY29yZXN9CnBhbmFzQ29tcG9zaXRlTmVnYXRpdmUgPC0gZmlsdGVyKHBhbmFzQ29tcG9zaXRlLCBhZmZlY3QgPT0gIm5lZ2F0aXZlIikgIyBuZXcgZGF0YSBmcmFtZSB3aXRoIG9ubHkgbmVnYXRpdmUgc2NvcmVzCgptb2RlbE5lZ2F0aXZlIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUocGFuYXNDb21wb3NpdGVOZWdhdGl2ZSksICMgUmVwZWF0ZWQgb3ZlciBzdWJqZWN0czsgdHlwZSAzIHN1bXMgb2Ygc3F1YXJlcyAoY2YuIFNQU1MpCiAgICAgICAgICAgICAgICAgICAgICAgIGR2ID0gLihzY29yZSksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sIHRpbWUpLCB0eXBlID0gMykKa2FibGUobW9kZWxOZWdhdGl2ZSkKCmBgYAoKU3ViamVjdHMnIG1vb2QgYWxzbyBiZWNvbWUgbGVzcyBuZWdhdGl2ZSBhZnRlciBzdGltdWxhdGlvbi4uLgoKIyMgdERDUyBzZW5zYXRpb25zCgpBZnRlciBlYWNoIHNlc3Npb24sIHN1YmplY3RzIGFsc28gY29tcGxldGVkIGEgcXVlc3Rpb25uYWlyZSBwcm9iaW5nIHREQ1Mgc2Vuc2F0aW9ucy4KCiMjIyBMb2FkIGRhdGEKCmBgYHtyIExvYWQgdERDUyBzZW5zYXRpb25zIGRhdGF9CiMgTG9hZCB0aGUgZGF0YSBmcmFtZQpkYXRhRmlsZSA8LSBmaWxlLnBhdGgoImRhdGEiLCAidGRjc19zZW5zYXRpb25zLmNzdiIpCnNlbnNEYXRhIDwtIHJlYWQuY3N2KGRhdGFGaWxlLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiOyIsIG5hLnN0cmluZ3MgPSAiIikKCmhlYWQoc2Vuc0RhdGEpICMgc2hvdyBkYXRhIGZyYW1lCmBgYAoKVGhleSB3ZXJlIGFza2VkIHRvIHdoaWNoIGRlZ3JlZSB0aGUgZm9sbG93aW5nIHNlbnNhdGlvbnMgd2VyZSBwcmVzZW50IGR1cmluZyBzdGltdWxhdGlvbjogX3RpbmdsaW5nXywgX2l0Y2hpbmcgc2Vuc2F0aW9uXywgX2J1cm5pbmcgc2Vuc2F0aW9uXywgX3BhaW5fLCBfaGVhZGFjaGVfLCBfZmF0aWd1ZV8sIF9kaXp6aW5lc3NfIGFuZCBfbmF1c2VhXy4gRWFjaCB3YXMgcmF0ZWQgb24gYSBzY2FsZSBmcm9tIDAtNDoKCjAuIG5vbmUKMS4gYSBsaXR0bGUKMi4gbW9kZXJhdGUKMy4gc3Ryb25nCjQuIHZlcnkgc3Ryb25nCgpUaGV5IGFsc28gcmF0ZWQgdGhlaXIgY29uZmlkZW5jZSBfdGhhdCB0aGUgc2Vuc2F0aW9ucyB3ZXJlIGNhdXNlZCBieSB0aGUgc3RpbXVsYXRpb25fIG9uIGEgc2NhbGUgZnJvbSAwLTQgKGNvbHVtbnMgc3RhcnRpbmcgd2l0aCBgY29uZi5gKToKCjAuIG4vYSAobWVhbmluZyB0aGV5IHJhdGVkIHRoZSBzZW5zYXRpb24gYSAwIG9uIHRoZSBwcmV2aW91cyBzY2FsZSkKMS4gdW5saWtlbHkKMi4gcG9zc2libHkKMy4gbGlrZWx5CjQuIHZlcnkgbGlrZWx5CgpGaW5hbGx5LCB0aGV5IGZpbGxlZCBpbiB3aGV0aGVyIHRoZXkgZmVsdCBvbmUgZWxlY3Ryb2RlIG1vcmUgdGhhbiB0aGUgb3RoZXIgKGBmZWx0Lm1vcmVgKTsgKGFuZCBpZiBzbywgd2hpY2ggYW5kIGZvciB3aGljaCBzZW5zYXRpb25zKS4KCl9fRmFjdG9yc19fOgoKKiBfc3ViamVjdF86IHN1YmplY3QgSUQgKGBTMDFgLCBgUzAyYCwgZXRjKQoqIF9zZXNzaW9uXzogV2hldGhlciBkYXRhIGFyZSBmcm9tIHRoZSBgZmlyc3RgIG9yIGBzZWNvbmRgIHNlc3Npb24KKiBfc3RpbXVsYXRpb25fOiBXaGV0aGVyIGRhdGEgYXJlIGZyb20gdGhlIGBhbm9kYWxgIG9yIGBjYXRob2RhbGAgc2Vzc2lvbgoKIyMjIFBsb3Qgc2Vuc2F0aW9uIGRpc3RyaWJ1dGlvbgoKYGBge3IgdERDUyBzZW5zYXRpb24gZGlzdHJpYnV0aW9uc30Kc2Vuc0RhdGEgJT4lCiAgc2VsZWN0KGV2ZXJ5dGhpbmcoKSwgLWNvbnRhaW5zKCJjb25mIiksIC1mZWx0Lm1vcmUpICU+JSAjIGRyb3AgdGhlIGNvbmZpZGVuY2UgY29sdW1ucwogIGdhdGhlcihzZW5zYXRpb24sIHJhdGluZywgaXRjaGluZzpuYXVzZWEpICU+JSAjIGdhdGhlciBzZW5zYXRpb25zIHNvIHRoZXkgY2FuIGJlIHVzZWQgYXMgYSBmYWN0b3IKICBnZ3Bsb3QoYWVzKHJhdGluZywgZmlsbCA9IHN0aW11bGF0aW9uKSkgKwogICAgZmFjZXRfd3JhcCh+c2Vuc2F0aW9uKSArCiAgICBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICJkb2RnZSIsIGJpbndpZHRoID0gMC41KSArCiAgICB4bGltKDAuNSw0LjUpICsKICAgIGdndGl0bGUoIlNlbnNhdGlvbnMgb3ZlciAxNSBhbm9kYWwgc2Vzc2lvbnMsIDE1IGNhdGhvZGFsIHNlc3Npb25zIikKYGBgCgpfTmF1c2VhXyB3YXMgbmV2ZXIgZXhwZXJpZW5jZWQ7IF9kaXp6aW5lc3NfIGFuZCBfcGFpbl8gYXJlIGFsc28gcmFyZSwgYW5kIG1pbGQuCgpfQnVybmluZ18sIF9pdGNoaW5nXyBhbmQgX3RpbmdsaW5nXyBhcmUgbW9zdCBmcmVxdWVudGx5IGV4cGVyaWVuY2VkIGFuZCB0byBhIGhpZ2hlciBkZWdyZWUuCgojIyMgUGxvdCBjb25maWRlbmNlIGRpc3RyaWJ1dGlvbnMKCmBgYHtyIHREQ1MgY29uZmlkZW5jZSBkaXN0cmlidXRpb25zfQpzZW5zRGF0YSAlPiUKICBzZWxlY3QoY29udGFpbnMoImNvbmYiKSwgc3ViamVjdCwgc2Vzc2lvbiwgc3RpbXVsYXRpb24pICU+JSAjIGRyb3AgdGhlIHJhdGluZyBjb2x1bW5zCiAgZ2F0aGVyKHNlbnNhdGlvbiwgcmF0aW5nLCBjb25mLml0Y2hpbmc6Y29uZi5uYXVzZWEpICU+JQogIGdncGxvdChhZXMocmF0aW5nLCBmaWxsID0gc3RpbXVsYXRpb24pKSArCiAgICBmYWNldF93cmFwKH5zZW5zYXRpb24pICsKICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImRvZGdlIiwgYmlud2lkdGggPSAwLjUpICsKICAgIHhsaW0oMC41LDQuNSkgKwogICAgZ2d0aXRsZSgiQ29uZmlkZW5jZSBvdmVyIDE1IGFub2RhbCBzZXNzaW9ucywgMTUgY2F0aG9kYWwgc2Vzc2lvbnMiKQpgYGAKCkZvciAibG9jYWwiIHNlbnNhdGlvbnMgbGlrZSBfYnVybmluZ18sIF90aW5nbGluZ18gYW5kIF9kaXp6aW5lc3NfLCBzdWJqZWN0cyBoYXZlIGhpZ2ggY29uZmlkZW5jZSB0aGF0IHRoZXNlIGFyZSBkdWUgdG8gdERDUy4gRm9yIG1vcmUgZGlmZnVzZSBzZW5zYXRpb25zLCBsaWtlIF9mYXRpZ3VlXyBhbmQgX2hlYWRhY2hlXywgcmF0aW5ncyBhcmUgdmVyeSBsb3csIHNvIHRoZWlyIG9jY3VyZW5jZSBtaWdodCBqdXN0IGJlIGR1ZSB0byBwZXJmb3JtaW5nIHRoZSB0YXNrIGZvciBhbiBleHRlbmRlZCBwZXJpb2Qgb2YgdGltZS4KCiMjIyBTZW5zYXRpb24gZGlmZmVyZW5jZSBiZXR3ZWVuIGFub2RlIGFuZCBjYXRob2RlCgpgYGB7ciBTZW5zYXRpb25zIGZvciBhbm9kZSBhbmQgY2F0aG9kZX0Kc2Vuc0RhdGEgJT4lCiAgc2VsZWN0KGZlbHQubW9yZSwgc3ViamVjdCwgc2Vzc2lvbiwgc3RpbXVsYXRpb24pICU+JSAjIGtlZXAgb25seSB0aGUgcmVsZXZhbnQgY29sdW1uCiAgbXV0YXRlKGZlbHQubW9yZSA9IGZhY3RvcihmZWx0Lm1vcmUsIGxldmVscyA9IGMoImFub2RlIiwgImVxdWFsIiwgImNhdGhvZGUiKSkpICU+JSAjIGtlZXAgY29sb3JzIGNvbnNpc3RlbnQKICBnZ3Bsb3QoYWVzKHN0aW11bGF0aW9uLCBmaWxsID0gZmVsdC5tb3JlKSkgKwogICAgZ2VvbV9iYXIoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IDE6MTUpCmBgYAoKVGhlcmUncyBhIHByZXR0eSBldmVuIHNwbGl0IGJldHdlZW4gd2hpY2ggZWxlY3Ryb2RlIHBlb3BsZSBmZWVsIHRoZSBtb3N0LCBzbyB0aGVyZSBkb24ndCBhcHBlYXIgdG8gYmUgd29ycmlzb21lIGJpYXNlcy4gCgpEdXJpbmcgYW5vZGFsIHN0aW11bGF0aW9uLCB0aGUgYW5vZGUgaXMgZmVsdCBtb3JlIHRoYW4gdGhlIGNhdGhvZGU7IGR1cmluZyBjYXRob2RhbCBzdGltdWxhdGlvbiB0aGUgY2F0aG9kZSBpcyBmZWx0IG1vcmUgdGhhbiB0aGUgYW5vZGUuIEluIG90aGVyIHdvcmRzLCB0aGUgZWxlY3Ryb2RlIG92ZXIgdGhlIEZFRiBpcyBhbHdheXMgZmVsdCBtb3JlIHRoYW4gdGhlIGZvcmVoZWFkIGVsZWN0cm9kZS4KCkFib3V0IGEgdGhpcmQgb2YgcGVvcGxlIGRpZCBub3QgaW5kaWNhdGUgdGhleSBmZWx0IG9uZSBtb3JlIHRoYW4gdGhlIG90aGVyOyB0aGlzIGlzIHNsaWdodGx5IG1vcmUgaW4gdGhlIGNhdGhvZGFsIHNlc3Npb24uCgojIyMgU3RhdGlzdGljcwoKV2Ugd2lsbCB0ZXN0IGZvciBldmVyeSBzZW5zYXRpb24gc2VwYXJhdGVseSB3aGV0aGVyIHRoZXJlIHdhcyBhIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgYW5vZGFsIGFuZCBjYXRob2RhbCBzZXNzaW9ucy4gTWFubi1XaGl0bmV5LVUgdGVzdHMgYXJlIG1vc3QgYXBwcm9wcmlhdGUgaGVyZSwgYXMgdGhlIGRhdGEgYXJlIG9yZGluYWwgKExpa2VydCkgYW5kIGRvIG5vdCBsb29rIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMjIyBJdGNoaW5nCgpgYGB7ciBULXRlc3QgZm9yIGl0Y2hpbmd9CndpbGNveC50ZXN0KHNlbnNEYXRhJGl0Y2hpbmdbc2Vuc0RhdGEkc3RpbXVsYXRpb24gPT0gImFub2RhbCJdLCBzZW5zRGF0YSRpdGNoaW5nW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJjYXRob2RhbCJdKQpgYGAKCiMjIyMgVGluZ2xpbmcKCmBgYHtyIFQtdGVzdCBmb3IgdGluZ2xpbmd9CndpbGNveC50ZXN0KHNlbnNEYXRhJHRpbmdsaW5nW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJhbm9kYWwiXSwgc2Vuc0RhdGEkdGluZ2xpbmdbc2Vuc0RhdGEkc3RpbXVsYXRpb24gPT0gImNhdGhvZGFsIl0pCmBgYAoKIyMjIyBCdXJuaW5nCgpgYGB7ciBULXRlc3QgZm9yIGJ1cm5pbmd9CndpbGNveC50ZXN0KHNlbnNEYXRhJGJ1cm5pbmdbc2Vuc0RhdGEkc3RpbXVsYXRpb24gPT0gImFub2RhbCJdLCBzZW5zRGF0YSRidXJuaW5nW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJjYXRob2RhbCJdKQpgYGAKCiMjIyMgUGFpbgoKYGBge3IgVC10ZXN0IGZvciBwYWlufQp3aWxjb3gudGVzdChzZW5zRGF0YSRwYWluW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJhbm9kYWwiXSwgc2Vuc0RhdGEkcGFpbltzZW5zRGF0YSRzdGltdWxhdGlvbiA9PSAiY2F0aG9kYWwiXSkKYGBgCgojIyMjIEhlYWRhY2hlCgpgYGB7ciBULXRlc3QgZm9yIGhlYWRhY2hlfQp3aWxjb3gudGVzdChzZW5zRGF0YSRoZWFkYWNoZVtzZW5zRGF0YSRzdGltdWxhdGlvbiA9PSAiYW5vZGFsIl0sIHNlbnNEYXRhJGhlYWRhY2hlW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJjYXRob2RhbCJdKQpgYGAKCiMjIyMgRmF0aWd1ZQoKYGBge3IgVC10ZXN0IGZvciBmYXRpZ3VlfQp3aWxjb3gudGVzdChzZW5zRGF0YSRmYXRpZ3VlW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJhbm9kYWwiXSwgc2Vuc0RhdGEkZmF0aWd1ZVtzZW5zRGF0YSRzdGltdWxhdGlvbiA9PSAiY2F0aG9kYWwiXSkKYGBgCgojIyMjIERpenppbmVzcwoKYGBge3IgVGVzdCBmb3IgZGl6emluZXNzfQp3aWxjb3gudGVzdChzZW5zRGF0YSRkaXp6aW5lc3Nbc2Vuc0RhdGEkc3RpbXVsYXRpb24gPT0gImFub2RhbCJdLCBzZW5zRGF0YSRkaXp6aW5lc3Nbc2Vuc0RhdGEkc3RpbXVsYXRpb24gPT0gImNhdGhvZGFsIl0pCmBgYAoKIyMjIyBOYXVzZWEKCmBgYHtyIFRlc3QgZm9yIG5hdXNlYX0Kd2lsY294LnRlc3Qoc2Vuc0RhdGEkbmF1c2VhW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJhbm9kYWwiXSwgc2Vuc0RhdGEkbmF1c2VhW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJjYXRob2RhbCJdKQpgYGAKCk5hdXNlYSB3YXMgcmF0ZWQgMCBieSBldmVyeW9uZSBmb3IgYm90aCBhbm9kYWwgYW5kIGNhdGhvZGFsLgoKIyBMb2FkIGV5ZSBkYXRhCgpUaGUgLmNzdiBmaWxlIHdpdGggdGhlIGV5ZSB0cmFja2luZyBkYXRhIHdhcyBjcmVhdGVkIGluIE1BVExBQi4KCmBgYHtyIExvYWQgdGhlIGRhdGEgZnJhbWUsIGVjaG89VFJVRX0KIyBMb2FkIHRoZSBkYXRhIGZyYW1lCmRhdGFGaWxlIDwtIGZpbGUucGF0aCgiZGF0YSIsICJzYWNjLXREQ1NfZGF0YS5jc3YiKQpncm91cERhdGEgPC0gcmVhZC5jc3YoZGF0YUZpbGUsIGhlYWRlciA9IFRSVUUsIG5hLnN0cmluZ3MgPSAiTmFOIikKCmBgYAoKYGBge3IgRm9ybWF0IGRhdGEgZnJhbWV9CiMgRm9ybWF0IGRhdGEgZnJhbWUKZ3JvdXBEYXRhIDwtIHNlbGVjdChncm91cERhdGEsIC1YKSAjIGRyb3AgZmluYWwgZW1wdHkgY29sdW1uIG5hbWVkICJYIgpncm91cERhdGEkbGVnIDwtIGZhY3Rvcihncm91cERhdGEkbGVnLCBsZXZlbHMgPSBjKCJwcmUiLCAidERDUyIsICJwb3N0IikpCmBgYAoKYGBge3IgU2hvdyBkYXRhIGZyYW1lfQprYWJsZShoZWFkKGdyb3VwRGF0YSkpCmBgYAoKKiBfX3N1YmplY3RfXzogc3ViamVjdCBJRGoKKiBfX3N0aW11bGF0aW9uX186IFdoZXRoZXIgZGF0YSBhcmUgZnJvbSB0aGUgYW5vZGFsIG9yIGNhdGhvZGFsIHNlc3Npb24KKiBfX2xlZ19fOiBXaGV0aGVyIGRhdGEgYXJlIGJlZm9yZSAoYHByZWApLCBkdXJpbmcgKGB0RENTYCksIG9yIGFmdGVyIChgcG9zdGApIHREQ1MKKiBfX2Jsb2NrX186IEFmdGVyIGVhY2ggYmxvY2sgcGFydGljaXBhbnQgaGFkIGEgYnJpZWYgYnJlYWsgYW5kIHRyYWNrZXIgd2FzIHJlY2FsaWJyYXRlZAoqIF9fdHJpYWxfXzogdHJpYWwgbnVtYmVyIHdpdGhpbiBhIGJsb2NrCiogX190eXBlX186CiAgICAqIGBsYXRlcmFsYCAtIGZpeGF0aW9uIGluIGNlbnRlciBvZiBkaXNwbGF5LCBzYWNjYWRlIG1hZGUgdG93YXJkcyB0aGUgcGVyaXBoZXJ5CiAgICAqIGBjZW50ZXJgIC0gZml4YXRpb24gaW4gcGVyaXBoZXJ5LCBzYWNjYWRlIG1hZGUgYmFjayB0b3dhcmRzIHRoZSBjZW50ZXIgb2YgdGhlIGRpc3BsYXkKKiBfX2RpcmVjdGlvbl9fOiBgbGVmdGAgZm9yIHNhY2NhZGVzIHRvd2FyZHMgdGhlIGxlZnQgb2YgY3VycmVudCBmaXhhdGlvbiBwb3NpdGlvbjsgYHJpZ2h0YCBmb3Igc2FjY2FkZXMgdG8gdGhlIHJpZ2h0CiogX19kZXZpYXRpb24uc3RhcnRfXyA6IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGZyb20gc2FjY2FkZSBzdGFydCBwb2ludCB0byBmaXhhdGlvbgoqIF9fZGV2aWF0aW9uLmVuZF9fOiBkaXN0YW5jZSAoaW4gdmlzdWFsIGFuZ2xlKSBmcm9tIHNhY2NhZGUgZW5kIHBvaW50IHRvIHRhcmdldCBsb2NhdGlvbgoqIF9fYW1wbGl0dWRlX186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGJldHdlZW4gc2FjY2FkZSBzdGFydCBhbmQgZW5kIHBvaW50CiogX19sYXRlbmN5X186IHRpbWUgKGluIG1zKSBmcm9tIHRhcmdldCBvbnNldCB0byBzdGFydCBvZiBzYWNjYWRlCgojIEJhc2ljIGluc3BlY3Rpb24KCiMjICBSZWFjdGlvbiB0aW1lIGRpc3RyaWJ1dGlvbnMKCiMjIyBIaXN0b2dyYW1zIGZvciBlYWNoIHN1YmplY3QgCgpgYGB7ciBIaXN0b2dyYW0gcGVyIHN1YmplY3QsIGZpZy53aWR0aD05LjZ9Cmhpc3RUeXBlIDwtIGdncGxvdChncm91cERhdGEsIGFlcyhsYXRlbmN5LCBmaWxsID0gdHlwZSkpICsKICBmYWNldF93cmFwKH5zdWJqZWN0LCBucm93ID0gMywgc2NhbGVzID0iZnJlZV95IikgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgY29sb3IgPSAiZ3JleTUwIiwgc2l6ZSA9IC4yKSArCiAgeGxpbSgtNTAsMzAwKQpoaXN0VHlwZQpgYGAKCl9fU3RyYXkgb2JzZXJ2YXRpb25zOl9fCgoqIENlbnRlciBzYWNjYWRlcyBhcmUgbXVjaCBmYXN0ZXIgdGhhbiBsYXRlcmFsLCB0aG91Z2ggbm90IHRvIHRoZSBzYW1lIGRlZ3JlZSBpbiBhbGwgc3ViamVjdHMKKiBTb21lIGhhdmUgYSBmYXQgc2hvcnQgbGF0ZW5jeSB0YWlsIC0gdG9vIGZhc3Qgc2FjY2FkZXMgdGhhdCBhcmUgdmlydHVhbGx5IGFsbCB0b3dhcmRzIHRoZSBjZW50ZXI6IFMwNSwgUzEwLCBTMTEKKiBTb21lIGFwcGVhciBiaW1vZGFsLCBidXQgd2hlbiBzcGxpdCBmb3IgdHlwZSB0aGlzIGlzIGdlbmVyYWxseSBiZWNhdXNlIGNlbnRlciBzYWNjYWRlcyBhcmUgZmFzdGVyOiBTMDUsIFMwNiwgUzExCiogU29tZSBhcmUgc3VwZXIgc2hhcnAgKFM4KTsgb3RoZXJzIHJlYWxseSBicm9hZCAoUzAxKQoqIFMwMSBoYXMgYSB2ZXJ5IHR5cGljYWwgbG9va2luZyBkaXN0cmlidXRpb24sIGJ1dCBzbG93CgojIyMgU3RpbXVsYXRpb24gZWZmZWN0cyBhY3Jvc3Mgc3ViamVjdHMKCmBgYHtyIERlbnNpdHk6IHN0aW11bGF0aW9uIGFjcm9zcyBzdWJqZWN0cywgZmlnLndpZHRoPTkuNn0KZGVucyA8LSBnZ3Bsb3QoZ3JvdXBEYXRhLCBhZXMobGF0ZW5jeSwgY29sb3IgPSBzdGltdWxhdGlvbiwgbGluZXR5cGUgPSBsZWcpKSArCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9kZW5zaXR5KCkgKwogIHhsaW0oMCwgMjUwKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCmRlbnMKYGBgCgojIyMgQW5vZGFsIHZzLiBjYXRob2RhbCBpbiBlYWNoIHN1YmplY3QKYGBge3IgRGVuc2l0eTogYW5vZGFsIHZzLiBjYXRob2RhbCBwZXIgc3ViamVjdCwgZmlnLndpZHRoPTkuNn0KZGVuc3REQ1MgPC0gZ2dwbG90KGdyb3VwRGF0YVtncm91cERhdGEkbGVnID09ICd0RENTJyAmIGdyb3VwRGF0YSR0eXBlID09ICJsYXRlcmFsIiwgXSwgYWVzKGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24pKSArCiAgZmFjZXRfd3JhcCh+c3ViamVjdCwgbnJvdyA9IDMsIHNjYWxlcyA9ImZyZWVfeSIpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgeGxpbSgwLCAyNTApICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKwogIGdndGl0bGUoJ0xhdGVyYWwgc2FjY2FkZXMsIHREQ1MgYmxvY2snKQpkZW5zdERDUwpgYGAKCiMjIyBBbm9kYWwgc2Vzc2lvbiBpbiBlYWNoIHN1YmplY3QKCmBgYHtyIERlbnNpdHk6IGFub2RhbCBwZXIgbGVnIGFuZCBzdWJqZWN0LCBmaWcud2lkdGg9OS42fQpkZW5zTGVnQW5vZGFsIDwtIGdncGxvdChncm91cERhdGFbZ3JvdXBEYXRhJHN0aW11bGF0aW9uID09ICdhbm9kYWwnICYgZ3JvdXBEYXRhJHR5cGUgPT0gImxhdGVyYWwiLCBdLCBhZXMobGF0ZW5jeSwgY29sb3IgPSBsZWcpKSArCiAgZmFjZXRfd3JhcCh+c3ViamVjdCwgbnJvdyA9IDMsIHNjYWxlcyA9ImZyZWVfeSIpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgeGxpbSgwLCAyNTApICsKICBnZ3RpdGxlKCdMYXRlcmFsIHNhY2NhZGVzLCBhbm9kYWwnKQpkZW5zTGVnQW5vZGFsCmBgYAoKIyMjIENhdGhvZGFsIHNlc3Npb24gaW4gZWFjaCBzdWJqZWN0CmBgYHtyIERlbnNpdHk6IGNhdGhvZGFsIHBlciBsZWcgYW5kIHN1YmplY3QsIGZpZy53aWR0aD05LjZ9CmRlbnNMZWdDYXRob2RhbCA8LSBnZ3Bsb3QoZ3JvdXBEYXRhW2dyb3VwRGF0YSRzdGltdWxhdGlvbiA9PSAnY2F0aG9kYWwnICYgZ3JvdXBEYXRhJHR5cGUgPT0gImxhdGVyYWwiLCBdLCBhZXMobGF0ZW5jeSwgY29sb3IgPSBsZWcpKSArCiAgZmFjZXRfd3JhcCh+c3ViamVjdCwgbnJvdyA9IDMsIHNjYWxlcyA9ImZyZWVfeSIpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgeGxpbSgwLCAyNTApICsKICBnZ3RpdGxlKCdMYXRlcmFsIHNhY2NhZGVzLCBjYXRob2RhbCcpCmRlbnNMZWdDYXRob2RhbApgYGAKCiMgT3V0bGllcnMKCiMjIE1hcmsgb3V0bGllcnMKCmBgYHtyIE91dGxpZXIgY3JpdGVyaWEsIGluY2x1ZGU9RkFMU0V9CnRvb0Zhc3Q9IDUwOwp0b29TbG93ID0gNDAwOyAKYmFkRml4ID0gMS44OwpiYWRTYWNjID0gODsKYGBgCgpDcml0ZXJpYSBmb3Igb3V0bGllcnM6CgoqIERpc2NhcmQgZmFzdCBzYWNjYWRlcywgd2l0aCBhIGxhdGVuY3kgb2YgYHIgdG9vRmFzdGAgbXMgb3IgbGVzcwoqIERpc2NhcmQgc2xvdyBzYWNjYWRlcywgc2FjY2FkZXMgd2l0aCBhIGxhdGVuY3kgb2YgYHIgdG9vU2xvd2AgbXMgb3IgbW9yZQoqIERpc2NhcmQgaW5hY2N1cmF0ZSBmaXhhdGlvbnMsIHdpdGggc2FjY2FkZSBzdGFydGluZyBwb2ludCBtb3JlIHRoYW4gYHIgYmFkRml4YCBkZWdyZWVzIG9yIG1vcmUgYXdheSBmcm9tIGZpeGF0aW9uCiogRGlzY2FyZCBmYXVsdHkgc2FjY2FkZXMsIHdpdGggc2FjY2FkZSBlbmQgcG9pbnQgbW9yZSB0aGFuIGByIGJhZFNhY2NgIGRlZ3JlZSBvciBtb3JlIGF3YXkgZnJvbSB0aGUgdGFyZ2V0CgpJbiBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSwgdGhpcyB3YXM6CgoqIEZhc3Qgc2FjY2FkZXM6IDUwIG1zCiogU2xvdyBzYWNjYWRlczogNDAwIG1zCiogQmFkIGZpeGF0aW9uczogMS44IGRlZ3JlZXMKKiBGYXVsdHkgc2FjY2FkZXM6IG9wcG9zaXRlIGhlbWlmaWVsZCBvZiB0YXJnZXQgKGhlcmUsIHRoYXQgd291bGQgYmUgOCBkZWdyZWVzIGFzIHRhcmdldHMgd2VyZSB0aGF0IGVjY2VudHJpYykKCmBgYHtyIE1hcmsgdHJpYWxzIGFzIG91dGxpZXJzfQojIE1hcmsgb3V0bGllcnMKZ3JvdXBEYXRhIDwtIG11dGF0ZShncm91cERhdGEsIG91dGxpZXIgPSBGQUxTRSwgIyBmaWxsIHZlY3RvciB3aXRoIEZBTFNFIGZvciBhbGwgdHJpYWxzCiAgICAgICAgICAgICAgICAgICAgb3V0bGllciA9IGlmZWxzZShsYXRlbmN5IDwgdG9vRmFzdCwgImZhc3QiLCBvdXRsaWVyKSwgIyBtYXJrIHRvbyBmYXN0IHRyaWFscyBhcyAiZmFzdCIKICAgICAgICAgICAgICAgICAgICBvdXRsaWVyID0gaWZlbHNlKGxhdGVuY3kgPiB0b29TbG93LCAic2xvdyIsIG91dGxpZXIpLCAjIG1hcmsgdG9vIHNsb3cgdHJpYWxzIGFzICJzbG93IgogICAgICAgICAgICAgICAgICAgIG91dGxpZXIgPSBpZmVsc2UoZGV2aWF0aW9uLnN0YXJ0ID4gYmFkRml4LCAiZml4YXRpb24iLCBvdXRsaWVyKSwgIyBtYXJrIGJhZCBmaXhhdGlvbnMgYXMgImZpeGF0aW9uIgogICAgICAgICAgICAgICAgICAgIG91dGxpZXIgPSBpZmVsc2UoZGV2aWF0aW9uLmVuZCA+IGJhZFNhY2MsICJzYWNjYWRlIiwgb3V0bGllcikpICMgbWFyayBpbmFjY3VyYXRlIHNhY2NhZGVzIGFzICJzYWNjYWRlIgoKZ3JvdXBEYXRhQ2xlYW4gPC0gZmlsdGVyKGdyb3VwRGF0YSwgb3V0bGllciA9PSBGQUxTRSkgIyBtYWtlIG5ldyBkYXRhIGZyYW1lIHdpdGhvdXQgb3V0bGllciB0cmlhbHMKYGBgCgojIyBQbG90IG91dGxpZXJzIHBlciBzdWJqZWN0CgpgYGB7ciBQbG90IG91dGxpZXJzIHBlciBzdWJqZWN0LCBmaWcud2lkdGg9OS42fQpvdXRsaWVyUGxvdCA8LSBnZ3Bsb3QoZ3JvdXBEYXRhW2dyb3VwRGF0YSRvdXRsaWVyICE9IEZBTFNFLCBdLCBhZXMoaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sbGVnLGJsb2NrLHRyaWFsKSwgbGF0ZW5jeSwgY29sb3IgPSBvdXRsaWVyLCBzaGFwZSA9IHR5cGUpKSArCiAgZmFjZXRfd3JhcCh+c3ViamVjdCwgbnJvdyA9IDQsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gdG9vRmFzdCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHRvb1Nsb3csIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICB4bGFiKCdUcmlhbCcpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksICMgcmVtb3ZlIHgtYXhpcyAoanVzdCB0cmlhbCBjb3VudCkKICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKQpvdXRsaWVyUGxvdApgYGAKCmBgYHtyIFRhYmxlIG9mIG91dGxpZXIgY291bnRzLCByZXN1bHRzPSdhc2lzJ30Kb3V0bGllckNvdW50IDwtIGdyb3VwRGF0YSAlPiUKICBncm91cF9ieShzdWJqZWN0KSAlPiUKICBzdW1tYXJpemUob3V0bGllcl9jb3VudCA9IHN1bShvdXRsaWVyICE9IEZBTFNFLCBuYS5ybSA9IFRSVUUpKQprYWJsZShvdXRsaWVyQ291bnQsIGNhcHRpb24gPSAiTnVtYmVyIG9mIG91dGxpZXIgdHJpYWxzIHBlciBzdWJqZWN0IikKYGBgCgpfX1N0cmF5IG9ic2VydmF0aW9uczpfXwoKRGlmZmVyZW5jZXMgYmV0d2VlbiBzdWJqZWN0czoKCiogU29tZSBzdWJqZWN0cyBoYXZlIGJhcmVseSBhbnkgb3V0bGllcnMgKFMwMiwgUzA3KQoqIE1vc3Qgc3ViamVjdHMgaGF2ZSBxdWl0ZSBhIGZldyBvdXRsaWVycywgZXNwZWNpYWxseSBTMDUsUzA2LCBTMTAgYW5kIFMxLiBUaGUgbWVhbiBpcyBgciByb3VuZChtZWFuKG91dGxpZXJDb3VudCRvdXRsaWVyX2NvdW50KSwgZGlnaXRzID0gMClgIG91dCBvZiBgciBzdW0oZ3JvdXBEYXRhJHN1YmplY3QgPT0gIlMwMSIpYCB0cmlhbHMgaW4gdG90YWwKKiBPbmx5IFMwMSBoYXMgYSBzaXphYmxlIGFtb3VudCBvZiBzbG93IHNhY2NhZGVzCiogUzE0IGhhcyBhIGxvdCBvZiBuZWdhdGl2ZSBsYXRlbmNpZXMgKGFuZCBhbHNvIGxvbmcgcG9zaXRpdmUgbGF0ZW5jaWVzKQoqIFRob3NlIHN1YmplY3RzIHdpdGggbWFueSBmYXN0IHNhY2NhZGVzIGFsc28gdGVuZCB0byBoYXZlIG1hbnkgYmFkIGZpeGF0aW9ucyAoUzA2LCBTMTAsIGJ1dCBzZWUgUzA4KQoKR2VuZXJhbCBwYXR0ZXJuczoKCiogT2NjdXJlbmNlIG9mIG91dGxpZXJzIHNlZW1zIHN0YWJsZSB0aHJvdWdob3V0IHRoZSBzZXNzaW9uOiB0aGVyZSBhcmVuJ3QgbW9yZS9sZXNzIGluIHRoZSBiZWdpbm5pbmcgLyBlbmQKKiBUaGVyZSBhcmUgdmVyeSBmZXcgaW5hY2N1cmF0ZSBzYWNjYWRlcyAobWFrZXMgc2Vuc2UsIGJlY2F1c2UgdGFzayBpcyBlYXN5IGFuZCBjcml0ZXJpb24gaXMgbm90IHN0cmljdCkKKiBNb3N0IG91dGxpZXJzIGFyZSB0b28gZmFzdCBzYWNjYWRlcyBhbmQgYmFkIGZpeGF0aW9ucwoqIFNsb3cgc2FjY2FkZXMgYXJlIGxhdGVyYWwsIGZhc3Qgc2FjY2FkZXMgYXJlIHRvIHRoZSBjZW50ZXIsIGJlY2F1c2Ugb25seSB0aGUgbGF0dGVyIGFyZSBwcmVkaWN0YWJsZQoqIEJhZCBmaXhhdGlvbnMgYXBwZWFyIHRvIGJlIG1vc3RseSBjZW50ZXIgc2FjY2FkZXMgKGJ1dCB0aGlzIHZhcmllcyBhIGxvdCkuIFBlcmhhcHMgdGhlIGV5ZXMgYWxyZWFkeSBkcmlmdCBiYWNrIHRvd2FyZHMgdGhlIGNlbnRlciwgYmVmb3JlIGV4ZWN1dGluZyB0aGUgc2FjY2FkZT8KKiBPciBpcyB0aGUgc291cmNlIG9mIGJhZCBmaXhhdGlvbnMgc2ltcGx5IHBvb3IgcXVhbGl0eSBvZiB0aGUgZXllIHRyYWNrZXIgZGF0YT8gZS5nLiBwZW9wbGUgYXJlIGFjdHVhbGx5IGZpeGF0aW5nLCBidXQgZHVlIHRvIGRyaWZ0IGl0IGFwcGVhcnMgdGhleSBhcmUgbm90LgoKIyBNZWRpYW4gcmVhY3Rpb24gdGltZQoKSGVyZSB3ZSBzaW1wbHkgZXh0cmFjdCBtZWRpYW4gUlRzIGZvciBlYWNoIGNvbmRpdGlvbiBhbmQgdXNlIGEgcmVwZWF0ZWQgbWVhc3VyZXMgQU5PVkEgZm9yIHN0YXRpc3RpY2FsIGFuYWx5c2lzLCBmb2xsb3dpbmcgW0thbmFpIGV0IGFsLiAoMjAxMildKGh0dHA6Ly9keC5kb2kub3JnLzEwLjMzODkvZnBzeXQuMjAxMi4wMDA0NSkuCgojIyBEYXRhIHBlciBibG9jawoKYGBge3IgQ29tcHV0ZSBtZWRpYW4gaW4gZWFjaCBjb25kaXRpb259CiMgQ29tcHV0ZSBtZWRpYW4gaW4gZWFjaCBjb25kaXRpb24KbGF0ZW5jeU1lZGlhbiA8LSBncm91cERhdGFDbGVhbiAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGxlZyxibG9jayx0eXBlLGRpcmVjdGlvbikgJT4lCiAgc3VtbWFyaXNlKGxhdGVuY3kgPSBtZWRpYW4obGF0ZW5jeSwgbmEucm0gPSBUUlVFKSkKYGBgCgojIyMgRnVsbCBmYWN0b3JpYWwgcGxvdAoKYGBge3IgRnVsbCBmYWN0b3JpYWwgcGxvdCwgZmlnLndpZHRoPTkuNn0KIyBQbG90IG91dCBhbGwgdGhlIGRhdGEKZnVsbFBsb3QgPC0gZ2dwbG90KGxhdGVuY3lNZWRpYW4sIGFlcyhpbnRlcmFjdGlvbihibG9jayxsZWcpLCBsYXRlbmN5LCBjb2xvciA9IHN0aW11bGF0aW9uLCBzaGFwZSA9IHN0aW11bGF0aW9uKSkgKwogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaXplID0gMykgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgc2l6ZSA9IDEpCmZ1bGxQbG90CmBgYAoKVGhlcmUgaXMgYSBwcmV0dHkgc2l6YWJsZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGFub2RhbCAmIGNhdGhvZGFsIHNlc3Npb25zIGluIHRoZSBiYXNlbGluZSBhbHJlYWR5OiBjYXRob2RhbCBpcyBhbHdheXMgZmFzdGVyIHRoYW4gYW5vZGFsLgoKVGhlIGFib3ZlIHBsb3QgYWxzbyBzaG93cyBhIGxvdCBvZiB2YXJpYWJpbGl0eSwgc28gaXQgbWlnaHQgYmUgYmVzdCB0byBhdmVyYWdlIG92ZXIgZWFjaCAzIGNvbnNlY3V0aXZlIGJsb2NrcyBzbyB0aGUgZGF0YSBjb21lIGluIDE1LW1pbnV0ZSBpbnRlcnZhbHMuCgojIyAxNS1taW51dGUgaW50ZXJ2YWxzIChjb2xsYXBzZSAzIGJsb2NrcykKCmBgYHtyIENvbXB1dGUgbWVkaWFuLCBjb2xsYXBzZWQgYWNyb3NzIGJsb2Nrc30KIyBDb21wdXRlIG1lZGlhbiBwZXIgbGVnCmxhdGVuY3lNZWRpYW5MZWcgPC0gZ3JvdXBEYXRhQ2xlYW4gJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixkaXJlY3Rpb24sdHlwZSkgJT4lIAogIHN1bW1hcmlzZShiYXNlbGluZSA9IG1lZGlhbihsYXRlbmN5W2xlZyA9PSAicHJlIl0sIG5hLnJtID0gVFJVRSksICMgdGFrZSBhdmVyYWdlIG9mIDMgYmxvY2tzLCBtYWtlIG5ldyBjb2x1bW4KICAgICAgICAgICAgdERDUyA9IG1lZGlhbihsYXRlbmN5W2xlZyA9PSAidERDUyJdLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBwb3N0LjEgPSBtZWRpYW4obGF0ZW5jeVtsZWcgPT0gInBvc3QiICYgYmxvY2sgPD0gM10sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHBvc3QuMiA9IG1lZGlhbihsYXRlbmN5W2xlZyA9PSAicG9zdCIgJiBibG9jayA+PSA0XSwgbmEucm0gPSBUUlVFKSkgJT4lCiBnYXRoZXIobGVnLGxhdGVuY3ksYmFzZWxpbmUsdERDUyxwb3N0LjEscG9zdC4yKSAlPiUgIyBnYXRoZXIgbmV3IGNvbHVtbnMgdG8gdXNlIGFzIGZhY3RvcgogbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgojIyMgTGluZSBwbG90IHBlciBsZWcsIGluZGl2aWR1YWwgc3ViamVjdHMKCk5vdyBtYWtlIHRoZSBzYW1lIHBsb3QsIGJ1dCBmb3IgdGhlIGRhdGEgY29sbGFwc2VkIG92ZXIgMyBibG9ja3MuIEFsc28gZHJhdyB0aGUgcGxvdCBmb3IgZWFjaCBpbmRpdmlkdWFsIHN1YmplY3QsIHNvIHdlIGNhbiBzZWUgd2hpY2ggc3ViamVjdHMgZHJpdmUgdGhlIGJhc2VsaW5lIGRpZmZlcmVuY2UsIGFuZCBpbiB3aGljaCBkaXJlY3Rpb24gdGhlIHN0aW11bGF0aW9uIGVmZmVjdCBnb2VzIGZvciBlYWNoIHN1YmplY3QgKGlmIHRoZXJlIGlzIGFueSkuCgpgYGB7ciBMaW5lIHBsb3QgZm9yIGVhY2ggc3ViamVjdCwgZmlnLndpZHRoPTkuNn0Ka2FuYWlTdWJzUGxvdCA8LSBnZ3Bsb3QobGF0ZW5jeU1lZGlhbkxlZywgYWVzKGxlZywgbGF0ZW5jeSwgY29sb3IgPSBzdGltdWxhdGlvbiwgc2hhcGUgPSB0eXBlKSkgKyAgICAgICAgIAogIGZhY2V0X3dyYXAofnN1YmplY3QsIG5yb3cgPSA1KSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAyKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pKQprYW5haVN1YnNQbG90CmBgYAoKVGhlcmUgYXJlIGEgY291cGxlIG9mIHN1YmplY3RzIHRoYXQgc2hvdyBsYXJnZSBkaWZmZXJlbmNlcyBpbiB0aGUgYmFzZWxpbmUgYWxyZWFkeSwgZXNwZWNpYWxseSBTMDEuCgojIyMgQ29tcHV0ZSBtYWduaXR1ZGUgb2YgYmFzZWxpbmUgZGlmZmVyZW5jZQoKTGV0J3MgbG9vayBhdCB0aGUgc2l6ZSBvZiB0aGUgYmFzZWxpbmUgZGlmZmVyZW5jZSBwZXIgc3ViamVjdC4gCgpgYGB7ciByZXN1bHRzID0gJ2FzaXMnfQpiYXNlbGluZURpZmYgPC0gbGF0ZW5jeU1lZGlhbkxlZyAlPiUgCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUgIyBrZWVwIG9ubHkgYmFzZWxpbmUgZGF0YQogIHNwcmVhZChzdGltdWxhdGlvbiwgbGF0ZW5jeSkgJT4lICMgbWFrZSBzZXBhcmF0ZSBjb2x1bW5zIGZvciBhbm9kYWwgYW5kIGNhdGhvZGFsCiAgbXV0YXRlKGxhdGVuY3kuZGlmZiA9IGFub2RhbCAtIGNhdGhvZGFsKSAlPiUgIyBzdWJ0cmFjdCB0aGUgZGlmZmVyZW5jZQogIGdyb3VwX2J5KHN1YmplY3QpICU+JSAKICBzdW1tYXJpc2UobGF0ZW5jeS5kaWZmID0gbWVhbihsYXRlbmN5LmRpZmYpKSMga2VlcCB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIHBlciBzdWJqZWN0CgprYWJsZShiYXNlbGluZURpZmYsIGNhcHRpb24gPSAnRGlmZmVyZW5jZSBiZXR3ZWVuIGJhc2VsaW5lIHNhY2NhZGUgbGF0ZW5jaWVzIGluIGFub2RhbCBhbmQgY2F0aG9kYWwgc2Vzc2lvbicpCmBgYAoKVGhlcmUgYXJlIGEgZmV3IHN1YmplY3RzIHdpdGggc3Vic3RhbnRpYWwgbGF0ZW5jeSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHNlc3Npb25zOyB0aGUgdGhyZWUgbGFyZ2VzdCBvZiB3aGljaCBhcmUgYWxsIHNsb3dlciBpbiB0aGUgYW5vZGFsIHNlc3Npb24gKHBvc2l0aXZlIHZhbHVlcykuIFRoZSBtZWFuIGRpZmZlcmVuY2UgaXMgYHIgcm91bmQobWVhbihiYXNlbGluZURpZmYkbGF0ZW5jeS5kaWZmKSwgZGlnaXRzID0gMSlgIG1zLgoKIyMjIEV4Y2x1ZGUgUzAxIGFuZCBTMTYKCkl0IHNlZW1zIHJlYXNvbmFibGUgdG8gZXhjbHVkZSBzdWJqZWN0IDEgZnJvbSBmdXJ0aGVyIGFuYWx5c2lzLCBiZWNhdXNlIG9mIHRocmVlIHRoaW5nczoKCiogUzAxIHNob3dzIHRoZSBsYXJnZXN0IGJhc2VsaW5lIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgYW5vZGFsIGFuZCBjYXRob2RhbCBzZXNzaW9ucy4KKiBPdmVyYWxsLCBTMDEgaXMgbXVjaCBzbG93ZXIgdGhhbiBhbGwgb3RoZXIgc3ViamVjdHMsIGJ5IHNldmVyYWwgdGVucyBvZiBtaWxsaXNlY29uZHMuCiogVGhlIGZpcnN0IHNlc3Npb24gZm9yIFMwMSB3YXMgYWJvcnRlZCBiZWNhdXNlIFMwMSB3YXMgbm90IGZlZWxpbmcgd2VsbC4gSXQgd2FzIHJlcGVhdGVkIGF0IGEgbGF0ZXIgZGF0ZSwgc28gUzAxIGNhbWUgdG8gdGhlIGxhYiAzIHRpbWVzIGluIHRvdGFsIGluc3RlYWQgb2YgdHdvLgoKSG93ZXZlciwgUzAxIGFsc28gc2VlbXMgdG8gc2hvdyB0aGUgbGFyZ2VzdCBlZmZlY3Qgb2Ygc3RpbXVsYXRpb24sIGZvciBib3RoIGFub2RhbCBhbmQgY2F0aG9kYWwgc3RpbXVsYXRpb24uIEl0IGlzIGV2ZW4gaW4gdGhlIGV4cGVjdGVkIGRpcmVjdGlvbjogZmFzdGVyIHNhY2NhZGVzIHRoYW4gYmFzZWxpbmUgaW4gdGhlIGFub2RhbCBzZXNzaW9uLCBzbG93ZXIgaW4gY2F0aG9kYWwuCgpTMTYncyBkYXRhIHF1YWxpdHkgd2FzIHBvb3IgaW4gdGhlIGZpcnN0IHNlc3Npb24gYW5kIGFsc28gc2hvd3MgYSBsYXJnZSBiYXNlbGluZSBkaWZmZXJlbmNlCgpgYGB7ciBFeGNsdWRlIFMwMSBhbmQgUzE2fQpsYXRlbmN5TWVkaWFuTGVnRXhjbCA8LSBmaWx0ZXIobGF0ZW5jeU1lZGlhbkxlZywgc3ViamVjdCAhPSAiUzAxIikgIyBkaXNjYXJkIHJvd3MgZnJvbSBTMDEKbGF0ZW5jeU1lZGlhbkxlZ0V4Y2wgPC0gZmlsdGVyKGxhdGVuY3lNZWRpYW5MZWcsIHN1YmplY3QgIT0gIlMxNiIpICMgZGlzY2FyZCByb3dzIGZyb20gUzE2CmxhdGVuY3lNZWRpYW5MZWdFeGNsJHN1YmplY3QgPC0gZmFjdG9yKGxhdGVuY3lNZWRpYW5MZWdFeGNsJHN1YmplY3QpICNyZW1ha2UgZmFjdG9yIGFzIGl0IG5vdyBoYXMgb25lIGxldmVsIGxlc3MKYGBgCgojIyMgTGluZSBwbG90IHBlciBsZWcgb3ZlciBhbGwgc3ViamVjdHMKCk5vdyB0aGF0IHdlJ3ZlIGV4Y2x1ZGVkIHN1YmplY3QocykgYW5kIGNvbGxhcHNlZCBkYXRhIG92ZXIgYmxvY2tzLCBsZXQncyBsb29rIGF0IHRoZSBncm91cCBhdmVyYWdlIHBsb3QgZm9yIHRoZSBmaXJzdCB0aW1lLgoKYGBge3IgTGluZSBwbG90IHBlciBsZWd9CmthbmFpUGxvdCA8LSBnZ3Bsb3QobGF0ZW5jeU1lZGlhbkxlZ0V4Y2wsIGFlcyhsZWcsIGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gc3RpbXVsYXRpb24pKSArICAgICAgICAgCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAzKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBzaXplID0gMSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjMpCmthbmFpUGxvdApgYGAKCkV2ZW4gd2l0aG91dCBTMDEsIHRoZXJlIGlzIHN0aWxsIGEgc21hbGwgYmFzZWxpbmUgZGlmZmVyZW5jZSBvZiBgciByb3VuZChtZWFuKGJhc2VsaW5lRGlmZiRsYXRlbmN5LmRpZmZbYmFzZWxpbmVEaWZmJHN1YmplY3QgIT0gIlMwMSJdKSwgZGlnaXRzID0gMSlgIG1zLiBUaGVyZSBhbHNvIHNlZW1zIHRvIGJlIGEgdGlueSBlZmZlY3QgaW4gdGhlIGNlbnRlci1sZWZ0IHNhY2NhZGUgY29uZGl0aW9uIHRoYXQncyBpbiB0aGUgZXhwZWN0ZWQgZGlyZWN0aW9uIGZvciBib3RoIHN0aW11bGF0aW9uIHNlc3Npb25zLCBidXQgaXQncyBhYm91dCB0aGUgc2l6ZSBvZiB0aGUgYmFzZWxpbmUgZGlmZmVyZW5jZS4KCiMjIFN1YnRyYWN0IGJhc2VsaW5lCgpUaGUgYmFzZWxpbmUgZGlmZmVyZW5jZSBpcyBub3QgaW5mb3JtYXRpdmUgYW5kIGNvdWxkIG9ic2N1cmUgcmVhbCBjaGFuZ2VzIGZyb20gYmFzZWxpbmUgd2l0aGluIHN1YmplY3RzLiBUaGVyZWZvcmUsIHN1YnRyYWN0IHRoZSBiYXNlbGluZSBmcm9tIGVhY2ggc3Vic2VxdWVudCBtZWFzdXJlbWVudC4KCmBgYHtyIFN1YnRyYWN0IGJhc2VsaW5lfQpsYXRlbmN5TWVkaWFuQmFzZWxpbmUgPC0gbGF0ZW5jeU1lZGlhbkxlZ0V4Y2wgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixkaXJlY3Rpb24sdHlwZSkgJT4lICMgZm9yIGVhY2ggY29uZGl0aW9uLCBzdWJ0cmFjdCBiYXNlbGluZSBzY29yZXMgYW5kIG1ha2UgbmV3IGNvbHVtbnMKICBzdW1tYXJpc2UodERDUyA9IGxhdGVuY3lbbGVnID09ICJ0RENTIl0gLSBsYXRlbmN5W2xlZyA9PSAiYmFzZWxpbmUiXSwgCiAgICAgICAgICAgcG9zdC4xID0gbGF0ZW5jeVtsZWcgPT0gInBvc3QuMSJdIC0gbGF0ZW5jeVtsZWcgPT0gImJhc2VsaW5lIl0sCiAgICAgICAgICAgcG9zdC4yID0gbGF0ZW5jeVtsZWcgPT0gInBvc3QuMiJdIC0gbGF0ZW5jeVtsZWcgPT0gImJhc2VsaW5lIl0pICU+JQogIGdhdGhlcihsZWcsIGxhdGVuY3ksIHREQ1MsIHBvc3QuMSwgcG9zdC4yKSAgJT4lICMgZ2F0aGVyIG5ldyBjb2x1bW5zIHRvIHVzZSBhcyBmYWN0b3IgCiAgbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgojIyMgTGluZSBwbG90cyBwZXIgbGVnIGZyb20gYmFzZWxpbmUKCmBgYHtyIExpbmUgcGxvdCBmcm9tIGJhc2VsaW5lfQprYW5haVBsb3RCYXNlIDwtIGdncGxvdChsYXRlbmN5TWVkaWFuQmFzZWxpbmUsIGFlcyhsZWcsIGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gc3RpbXVsYXRpb24pKSArICAgICAgICAgCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaXplID0gMykgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgc2l6ZSA9IDEpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC4zKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xNSwxNSkpCmthbmFpUGxvdEJhc2UKYGBgCgpBbGwgY2hhbmdlcyBmcm9tIGJhc2VsaW5lIGFyZSByZWFsbHkgdGlueTogNSBtcyBvciBsZXNzLgoKIyMjIEluZGl2aWR1YWwgc3ViamVjdHMsIGFub2RhbCBzZXNzaW9uCgpgYGB7ciBMaW5lIHBsb3QgcGVyIHN1YmplY3QgLSBhbm9kYWx9CmthbmFpUGxvdEJhc2VTdWJzQW5vZGFsIDwtIGdncGxvdChsYXRlbmN5TWVkaWFuQmFzZWxpbmVbbGF0ZW5jeU1lZGlhbkJhc2VsaW5lJHN0aW11bGF0aW9uID09ICJhbm9kYWwiLCBdLCBhZXMobGVnLCBsYXRlbmN5KSkgKwogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwPXN1YmplY3QsY29sb3I9c3ViamVjdCkpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBzdGltdWxhdGlvbiksIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKwogIGdndGl0bGUoIkFub2RhbCBkaWZmZXJlbmNlIGZyb20gYmFzZWxpbmUiKQprYW5haVBsb3RCYXNlU3Vic0Fub2RhbApgYGAKCkZvciB0aGUgY2VudGVyIHNhY2NhZGVzLCBtb3N0IHN1YmplY3RzIGZvbGxvdyB0aGUgZXhwZWN0ZWQgZGlyZWN0aW9uIGFuZCBhcmUgYmVsb3cgdGhlIGxpbmUuIFRoZSBsZWZ0LWxhdGVyYWwgZWZmZWN0IHRoYXQgaXMgb2YgcHJpbWFyeSBpbnRlcmVzdCBpcyBlcnJhdGljIHRob3VnaDogb25seSB+MTAgc3ViamVjdHMgYXJlIGJlbG93IHRoZSBsaW5lLCBhbmQgbm9uZSBzaG93IGFuIG9ubGluZS1lZmZlY3QgbGFyZ2VyIHRoYW4gMTIgbXMuCgojIyMgSW5kaXZpZHVhbCBzdWJqZWN0cywgY2F0aG9kYWwgc2Vzc2lvbgoKYGBge3IgTGluZSBwbG90IHBlciBzdWJqZWN0IC0gY2F0aG9kYWx9CmthbmFpUGxvdEJhc2VTdWJzQ2F0aG9kYWwgPC0gZ2dwbG90KGxhdGVuY3lNZWRpYW5CYXNlbGluZVtsYXRlbmN5TWVkaWFuQmFzZWxpbmUkc3RpbXVsYXRpb24gPT0gImNhdGhvZGFsIiwgXSwgYWVzKGxlZywgbGF0ZW5jeSkpICsKICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cD1zdWJqZWN0LGNvbG9yPXN1YmplY3QpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBnZW9tID0gImxpbmUiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIpICsgCiAgZ2d0aXRsZSgiQ2F0aG9kYWwgZGlmZmVyZW5jZSBmcm9tIGJhc2VsaW5lIikKa2FuYWlQbG90QmFzZVN1YnNDYXRob2RhbApgYGAKCkFsbCBvZiB0aGlzIGlzIHNwbGl0IHByZXR0eSBtdWNoIDUwLTUwLCBoZW5jZSB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGhvdmVyaW5nIGFyb3VuZCAwLgoKIyMgU3RhdGlzdGljcwoKIyMjIFQtdGVzdHMgZm9yIGJhc2VsaW5lIGRpZmZlcmVuY2VzCgpGaXJzdCwgdGVzdCBmb3IgYmFzZWxpbmUgZGlmZmVyZW5jZXMgZm9yIGVhY2ggY29tYmluYXRpb24gb2YgRElSRUNUSU9OIChsZWZ0LCByaWdodCkgYW5kIFRZUEUgKGNlbnRlciwgbGF0ZXJhbCkuCgpgYGB7ciBULXRlc3RzIGZvciBiYXNlbGluZSBkaWZmZXJlbmNlc30KCiMga2VlcCBvbmx5IHRoZSBiYXNlbGluZSBmb3IgbGVmdC1sYXRlcmFsLXNhY2NhZGVzCmxhdGVuY3lNZWRpYW5QcmVMZWZ0TGF0ZXJhbCA8LSBsYXRlbmN5TWVkaWFuTGVnRXhjbCAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIsIHR5cGUgPT0gImxhdGVyYWwiLCBkaXJlY3Rpb24gPT0gImxlZnQiKSAlPiUKICBzZWxlY3QoLWxlZywtdHlwZSwtZGlyZWN0aW9uKSAlPiUKICBzcHJlYWQoc3RpbXVsYXRpb24sIGxhdGVuY3kpCgojIGtlZXAgb25seSB0aGUgYmFzZWxpbmUgZm9yIHJpZ2h0LWxhdGVyYWwtc2FjY2FkZXMKbGF0ZW5jeU1lZGlhblByZVJpZ2h0TGF0ZXJhbCA8LSBsYXRlbmN5TWVkaWFuTGVnRXhjbCAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIsIHR5cGUgPT0gImxhdGVyYWwiLCBkaXJlY3Rpb24gPT0gInJpZ2h0IikgJT4lCiAgc2VsZWN0KC1sZWcsLXR5cGUsLWRpcmVjdGlvbikgJT4lCiAgc3ByZWFkKHN0aW11bGF0aW9uLCBsYXRlbmN5KQoKIyBrZWVwIG9ubHkgdGhlIGJhc2VsaW5lIGZvciByaWdodC1jZW50ZXItc2FjY2FkZXMKbGF0ZW5jeU1lZGlhblByZVJpZ2h0Q2VudGVyIDwtIGxhdGVuY3lNZWRpYW5MZWdFeGNsICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIiwgdHlwZSA9PSAiY2VudGVyIiwgZGlyZWN0aW9uID09ICJyaWdodCIpICU+JQogIHNlbGVjdCgtbGVnLC10eXBlLC1kaXJlY3Rpb24pICU+JQogIHNwcmVhZChzdGltdWxhdGlvbiwgbGF0ZW5jeSkKCiMga2VlcCBvbmx5IHRoZSBiYXNlbGluZSBmb3IgbGVmdC1jZW50ZXItc2FjY2FkZXMKbGF0ZW5jeU1lZGlhblByZUxlZnRDZW50ZXIgPC0gbGF0ZW5jeU1lZGlhbkxlZ0V4Y2wgJT4lCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiLCB0eXBlID09ICJjZW50ZXIiLCBkaXJlY3Rpb24gPT0gImxlZnQiKSAlPiUKICBzZWxlY3QoLWxlZywtdHlwZSwtZGlyZWN0aW9uKSAlPiUKICBzcHJlYWQoc3RpbXVsYXRpb24sIGxhdGVuY3kpCgp0LnRlc3QobGF0ZW5jeU1lZGlhblByZUxlZnRMYXRlcmFsJGFub2RhbCxsYXRlbmN5TWVkaWFuUHJlTGVmdExhdGVyYWwkY2F0aG9kYWwsIHBhaXJlZCA9IFRSVUUgKQp0LnRlc3QobGF0ZW5jeU1lZGlhblByZVJpZ2h0TGF0ZXJhbCRhbm9kYWwsbGF0ZW5jeU1lZGlhblByZVJpZ2h0TGF0ZXJhbCRjYXRob2RhbCwgcGFpcmVkID0gVFJVRSApCnQudGVzdChsYXRlbmN5TWVkaWFuUHJlTGVmdENlbnRlciRhbm9kYWwsbGF0ZW5jeU1lZGlhblByZUxlZnRDZW50ZXIkY2F0aG9kYWwsIHBhaXJlZCA9IFRSVUUgKQp0LnRlc3QobGF0ZW5jeU1lZGlhblByZVJpZ2h0Q2VudGVyJGFub2RhbCxsYXRlbmN5TWVkaWFuUHJlUmlnaHRDZW50ZXIkY2F0aG9kYWwsIHBhaXJlZCA9IFRSVUUgKQpgYGAKCk5vbmUgb2YgdGhlIGJhc2VsaW5lIGRpZmZlcmVuY2VzIGFyZSBzaWduaWZpY2FudCwgc28gdGhlcmUgaXMgcmVhc29uIHRvIGxlYXZlIHRoZSBiYXNlbGluZSBkYXRhIGluIHRoZSByZXN0IG9mIHRoZSBhbmFseXNlcy4KCiMjIyBPbW5pYnVzIGFub3ZhIC0gc2FjY2FkZSBsYXRlbmN5CgpfX0RhdGFfXzogT3V0bGllcnMgcmVtb3ZlZCwgY29sbGFwZXNlZCBpbnRvIDE1LW1pbnV0ZSBpbnRlcnZhbHMuIAoKX19EZXBlbmRlbnQgbWVhc3VyZV9fOiBzYWNjYWRpYyBsYXRlbmN5CgpfX0ZhY3RvcnNfXzoKCiogU1RJTVVMQVRJT04gKGFub2RhbCB2cy4gY2F0aG9kYWwpCiogTEVHIChiYXNlbGluZSwgdERDUywgcG9zdC4xLCBwb3N0LjIpCiogVFlQRSAobGF0ZXJhbCB2cy4gY2VudGVyKQoqIERJUkVDVElPTiAobGVmdCB2cy4gcmlnaHQpCgpgYGB7ciBPbW5pYnVzIEFOT1ZBLCByZXN1bHRzPSdhc2lzJ30KbW9kZWxPbW5pIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUobGF0ZW5jeU1lZGlhbkxlZ0V4Y2wpLCAjIFJlcGVhdGVkIG92ZXIgc3ViamVjdHM7IHR5cGUgMyBzdW1zIG9mIHNxdWFyZXMgKGNmLiBTUFNTKQogICAgICAgICAgICAgICAgICAgICAgICBkdiA9IC4obGF0ZW5jeSksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sIGxlZywgdHlwZSwgZGlyZWN0aW9uKSwgdHlwZSA9IDMpCmthYmxlKG1vZGVsT21uaSRBTk9WQSkKYGBgCgojIyMjIE1haW4gZWZmZWN0OiB0eXBlCgpgYGB7ciBNYWluIGVmZmVjdCBvZiB0eXBlfQpsYXRlbmN5TWVkaWFuTGVnRXhjbCAlPiUKICBncm91cF9ieShzdWJqZWN0LHR5cGUpICU+JQogIHN1bW1hcmlzZShsYXRlbmN5ID0gbWVhbihsYXRlbmN5KSkgJT4lCiAgZ2dwbG90KGFlcyh0eXBlLCBsYXRlbmN5KSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBzaXplID0gMSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yNSkKYGBgCgpUaGlzIHNpbXBseSByZWZsZWN0cyB0aGF0IGNlbnRlciBzYWNjYWRlcyBhcmUgZmFzdGVyIHRoYW4gbGF0ZXJhbCBzYWNjYWRlcywgYmVjYXVzZSB0aGUgbG9jYXRpb24gb2YgdGhlIHRhcmdldCBpcyBrbm93bi4KCiMjIyMgSW50ZXJhY3Rpb246IGxlZyBieSB0eXBlCgpgYGB7ciBJbnRlcmFjdGlvbiBsZWcgYnkgdHlwZX0KbGF0ZW5jeU1lZGlhbkxlZ0V4Y2wgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxsZWcsdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGxhdGVuY3kgPSBtZWFuKGxhdGVuY3kpKSAlPiUKICBnZ3Bsb3QoYWVzKGxlZywgbGF0ZW5jeSwgc2hhcGUgPSB0eXBlKSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gdHlwZSwgbGluZXR5cGUgPSB0eXBlKSkKYGBgCgpUaGUgZWZmZWN0IG9mIFRZUEUgYmVjb21lcyBsYXJnZXIgb3ZlciB0aW1lOiBjZW50ZXIgc2FjY2FkZXMgZ2V0IGZhc3RlciwgbGF0ZXJhbCBzYWNjYWRlcyBiZWNvbWUgc2xvd2VyLgoKIyMjIyBJbnRlcmFjdGlvbjogbGVnIGJ5IHR5cGUgYnkgZGlyZWN0aW9uCgpgYGB7ciBJbnRlcmFjdGlvbiBsZWcgYnkgdHlwZSBieSBkaXJlY3Rpb259CmxhdGVuY3lNZWRpYW5MZWdFeGNsICU+JQogIGdyb3VwX2J5KHN1YmplY3QsbGVnLHR5cGUsZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMobGVnLCBsYXRlbmN5LCBzaGFwZSA9IHR5cGUpKSArCiAgZmFjZXRfd3JhcCh+ZGlyZWN0aW9uKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gImxpbmUiLCBhZXMoZ3JvdXAgPSB0eXBlLCBsaW5ldHlwZSA9IHR5cGUpKQpgYGAKClRoaXMgaW50ZXJhY3Rpb24gb2YgTEVHIGFuZCBUWVBFIGFwcGVhcnMgdG8gb2NjdXIgdG8gYSBsZXNzZXIgZXh0ZW50IGZvciBsZWZ0IHNhY2NhZGVzLiBUaGUgInREQ1MiIGJsb2NrIGlzIHRoZSBkZXZpYW50IGhlcmUsIGJ1dCB0aGVyZSBpcyBubyBpbnRlcmFjdGlvbiB3aXRoIHN0aW11bGF0aW9uLgoKIyMjIEFOT1ZBIG1hdGNoaW5nIEthbmFpIGV0IGFsLiAoMjAxMikgLSBzYWNjYWRlIGxhdGVuY3kKCkRpZmZlcmluZyBmcm9tIHRoZSBwcmV2aW91cyBvbW5pYnVzIGFuYWx5c2lzLCBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSBhbmFseXNlZCBzaGlmdHMgZnJvbSBiYXNlbGluZSBhbmQgb25seSBoYWQgbGF0ZXJhbCBzYWNjYWRlcy4KCl9fRGF0YV9fOiAKCiogT3V0bGllcnMgcmVtb3ZlZAoqIENvbGxhcHNlZCBpbnRvIDE1LW1pbnV0ZSBpbnRlcnZhbHMKKiBTdWJ0cmFjdCB0aGUgYmFzZWxpbmUgZnJvbSBlYWNoIHN1YnNlcXVlbnQgYmxvY2sKKiBEaXNjYXJkIGNlbnRlciwga2VlcCBvbmx5IGxhdGVyYWwgc2FjY2FkZXMKCl9fRGVwZW5kZW50IG1lYXN1cmVfXzogc2FjY2FkaWMgbGF0ZW5jeQoKX19GYWN0b3JzX186CgoqIFNUSU1VTEFUSU9OIChhbm9kYWwgdnMuIGNhdGhvZGFsKQoqIExFRyAodERDUywgcG9zdC4xLCBwb3N0LjIpCiogRElSRUNUSU9OIChsZWZ0IHZzLiByaWdodCkKCmBgYHtyIEthbmFpIEFOT1ZBLCByZXN1bHRzPSdhc2lzJ30KCmxhdGVuY3lNZWRpYW5CYXNlbGluZUxhdGVyYWwgPC0gZmlsdGVyKGxhdGVuY3lNZWRpYW5CYXNlbGluZSwgdHlwZSA9PSAibGF0ZXJhbCIpICMga2VlcCBvbmx5IGxhdGVyYWwgc2FjY2FkZXMKCm1vZGVsS2FuYWkgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShsYXRlbmN5TWVkaWFuQmFzZWxpbmVMYXRlcmFsKSwKICAgICAgICAgICAgICAgICAgICAgICAgZHYgPSAuKGxhdGVuY3kpLCB3aWQgPSAuKHN1YmplY3QpLCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24pLCB0eXBlID0gMykKCiMgT1IsIHdpdGhvdXQgdGhlIEVaIHBhY2thZ2U6CiMgbW9kZWxLYW5haT1hb3YobGF0ZW5jeX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uICsgRXJyb3Ioc3ViamVjdC8oc3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbikpLGRhdGE9bGF0ZW5jeU1lZGlhbkJhc2VsaW5lTGF0ZXJhbCkKIyBzdW1tYXJ5KG1vZGVsS2FuYWkpCgprYWJsZShtb2RlbEthbmFpJEFOT1ZBKQpgYGAKCiMjIyMgTWFpbiBlZmZlY3Qgb2YgZGlyZWN0aW9uCgpgYGB7ciBNYWluIGVmZmVjdCBvZiBkaXJlY3Rpb259CmxhdGVuY3lNZWRpYW5CYXNlbGluZUxhdGVyYWwgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxkaXJlY3Rpb24pICU+JQogIHN1bW1hcmlzZShsYXRlbmN5ID0gbWVhbihsYXRlbmN5KSkgJT4lCiAgZ2dwbG90KGFlcyhkaXJlY3Rpb24sIGxhdGVuY3kpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBzaXplID0gMSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yNSkKYGBgCgpSaWdodCBzYWNjYWRlcyBiZWNvbWUgc2xvd2VyIHdpdGggcmVzcGVjdCB0byB0aGUgYmFzZWxpbmU7IGxlZnQgc2FjY2FkZXMgZG8gbm90LiBIb3dldmVyLCB0aGUgZWZmZWN0IGlzIHRpbnkgKDEtMiBtcykgYW5kIHRoZXJlIGlzIG5vIGludGVyYWN0aW9uIHdpdGggU1RJTVVMQVRJT04uCgojIyMgQU5PVkEgbWF0Y2hpbmcgS2FuYWkgZXQgYWwuICgyMDEyKSAtIGNlbnRlciBzYWNjYWRlcwoKUmVwZWF0IHRoZSBzYW1lIEFOT1ZBLCBidXQgbm93IGZvciBjZW50ZXIgc2FjY2FkZXMgKHdoaWNoIEthbmFpIGRpZCBub3QgaGF2ZSkuCgpgYGB7ciBLYW5haSBBTk9WQSBjZW50ZXIsIHJlc3VsdHM9J2FzaXMnfQoKbGF0ZW5jeU1lZGlhbkJhc2VsaW5lQ2VudGVyIDwtIGZpbHRlcihsYXRlbmN5TWVkaWFuQmFzZWxpbmUsIHR5cGUgPT0gImNlbnRlciIpICMga2VlcCBvbmx5IGxhdGVyYWwgc2FjY2FkZXMKCm1vZGVsS2FuYWlDZW50ZXIgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShsYXRlbmN5TWVkaWFuQmFzZWxpbmVDZW50ZXIpLAogICAgICAgICAgICAgICAgICAgICAgICBkdiA9IC4obGF0ZW5jeSksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksIHR5cGUgPSAzKQoKIyBPUiwgd2l0aG91dCB0aGUgRVogcGFja2FnZToKIyBtb2RlbEthbmFpPWFvdihsYXRlbmN5fnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24gKyBFcnJvcihzdWJqZWN0LyhzdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uKSksZGF0YT1sYXRlbmN5TWVkaWFuQmFzZWxpbmVMYXRlcmFsKQojIHN1bW1hcnkobW9kZWxLYW5haSkKCmthYmxlKG1vZGVsS2FuYWlDZW50ZXIkQU5PVkEpCmBgYAoKIyMjIEFOT1ZBIHdpdGhvdXQgc3VidHJhY3RpbmcgYmFzZWxpbmUsIGZvciBsYXRlcmFsIHNhY2NhZGVzIC0gc2FjY2FkZSBsYXRlbmN5CgpLYW5haSBldCBhbC4gYW5hbHl6ZWQgdGhlIGJhc2VsaW5lLXN1YnRyYWN0ZWQgZGF0YTsgbm93IHJlcGVhdCB0aGUgc2FtZSBBTk9WQSB3aXRoIHRoZSBiYXNlbGluZSBibG9jayBzdGlsbCBwcmVzZW50LgoKX19EYXRhX186IAoKKiBPdXRsaWVycyByZW1vdmVkCiogQ29sbGFwc2VkIGludG8gMTUtbWludXRlIGludGVydmFscwoqIERpc2NhcmQgY2VudGVyLCBrZWVwIG9ubHkgbGF0ZXJhbCBzYWNjYWRlcwoKX19EZXBlbmRlbnQgbWVhc3VyZV9fOiBzYWNjYWRpYyBsYXRlbmN5CgpfX0ZhY3RvcnNfXzoKCiogU1RJTVVMQVRJT04gKGFub2RhbCB2cy4gY2F0aG9kYWwpCiogTEVHICh0RENTLCBwb3N0LjEsIHBvc3QuMikKKiBESVJFQ1RJT04gKGxlZnQgdnMuIHJpZ2h0KQoKYGBge3IgTGF0ZXJhbCBzYWNjYWRlIEFOT1ZBLCByZXN1bHRzPSdhc2lzJ30KCiMga2VlcCBvbmx5IGxhdGVyYWwgc2FjY2FkZXMKbGF0ZW5jeU1lZGlhbkxhdGVyYWwgPC0gbGF0ZW5jeU1lZGlhbkxlZ0V4Y2wgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImxhdGVyYWwiKSAlPiUKICBzZWxlY3QoLXR5cGUpCgptb2RlbExhdGVyYWwgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShsYXRlbmN5TWVkaWFuTGF0ZXJhbCksCiAgICAgICAgICAgICAgICAgICAgICAgIGR2ID0gLihsYXRlbmN5KSwgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbiwgbGVnLCBkaXJlY3Rpb24pLCB0eXBlID0gMykKa2FibGUobW9kZWxMYXRlcmFsJEFOT1ZBKQoKYGBgCgojIyMgTGVnIGJ5IGRpcmVjdGlvbiBpbnRlcmFjdGlvbgoKYGBge3IgSW50ZXJhY3Rpb24gbGVnIGJ5IGRpcmVjdGlvbn0KbGF0ZW5jeU1lZGlhbkxhdGVyYWwgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxsZWcsZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMobGVnLCBsYXRlbmN5LCBzaGFwZSA9IGRpcmVjdGlvbikpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IGRpcmVjdGlvbiwgbGluZXR5cGUgPSBkaXJlY3Rpb24pKQpgYGAKClByZXR0eSBlcnJhdGljIHBhdHRlcm4sIGFuZCBubyBpbnRlcmFjdGlvbiB3aXRoIFNUSU1VTEFUSU9OIGVpdGhlci4KCiMjIyBBTk9WQSB3aXRob3V0IHN1YnRyYWN0aW5nIGJhc2VsaW5lLCBmb3IgY2VudGVyIHNhY2NhZGVzIC0gc2FjY2FkZSBsYXRlbmN5CgpTYW1lIGFzIHByZXZpb3VzLCBidXQgbm93IGZvciBjZW50ZXIgc2FjY2FkZXMuCgpgYGB7ciBDZW50ZXIgc2FjY2FkZSBBTk9WQSwgcmVzdWx0cz0nYXNpcyd9CmxhdGVuY3lNZWRpYW5DZW50ZXIgPC0gbGF0ZW5jeU1lZGlhbkxlZ0V4Y2wgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNlbnRlciIpICU+JQogIHNlbGVjdCgtdHlwZSkKCm1vZGVsQ2VudGVyIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUobGF0ZW5jeU1lZGlhbkNlbnRlciksCiAgICAgICAgICAgICAgICAgICAgICAgIGR2ID0gLihsYXRlbmN5KSwgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLigKICAgICAgICAgICAgICAgICAgICAgICAgICBzdGltdWxhdGlvbiwgbGVnLCBkaXJlY3Rpb24pLCB0eXBlID0gMykKa2FibGUobW9kZWxDZW50ZXIkQU5PVkEpCmBgYAoKIyMjIEJheWVzaWFuIGxpbmVhciBtaXhlZCBlZmZlY3RzIG1hdGNoaW5nIEthbmFpIC0gc2FjY2FkZSBsYXRlbmN5CgojIyMjIFRlc3QgYWdhaW5zdCB0aGUgbnVsbCBtb2RlbAoKYGBge3IgQ29tcHV0ZSBCYXllcyBGYWN0b3JzIGNmLiBudWxsIG1vZGVsfQpiZkthbmFpTnVsbCA9IGFub3ZhQkYobGF0ZW5jeX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKGxhdGVuY3lNZWRpYW5CYXNlbGluZUxhdGVyYWwpLCB3aGljaE1vZGVscz0id2l0aG1haW4iLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZLYW5haU51bGwgPSBzb3J0KGJmS2FuYWlOdWxsLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKYGBgCgpGaXJzdCB3ZSBjb21wYXJlIGFsbCBtb2RlbHMgdG8gdGhlIG1vc3Qgc2ltcGxlIChudWxsKSBtb2RlbCwgd2hpY2ggaXMgdGhlIGludGVyY2VwdCBvbmx5ICsgcmFuZG9tIGVmZmVjdCBtb2RlbDogYGxhdGVuY3kgfiBzdWJqZWN0YC4gVGhpcyBkb2VzIG5vdCB0ZXN0IGZvciBlZmZlY3RzIG9mIFNVQkpFQ1QgYnV0IG1vZGVscyBpdCBhcyBhIG51aXNhbmNlIGZhY3RvciAoYHdoaWNoUmFuZG9tID0gInN1YmplY3QiYCkuIEluIGFkZGl0aW9uLCB0byBkZWNyZWFzZSB0aGUgbW9kZWwgc3BhY2UsIHdlIGRvIG5vdCBjb25zaWRlciBtb2RlbHMgdGhhdCBoYXZlIGFuIGludGVyYWN0aW9uIHdpdGhvdXQgdGhlIGNvcnJlc3BvbmRpbmcgbWFpbiBlZmZlY3RzIChgd2hpY2hNb2RlbHMgPSAid2l0aG1haW4iYCkuCgpgYGB7ciBFeHRyYWN0IEJheWVzIEZhY3RvcnMgd2l0aE1haW4sIHJlc3VsdHM9J2FzaXMnfQprYWJsZShzZWxlY3QoZXh0cmFjdEJGKGJmS2FuYWlOdWxsKSwgYmYpKSAjIHNob3cgb25seSB0aGUgQmF5ZXMgZmFjdG9ycyBpbiBhIHRhYmxlCmBgYAoKVGhlIHdpbm5pbmcgbW9kZWwgaXMgdGhlIG9uZSB3aXRoIGFsbCBtYWluIGVmZmVjdHMsIHdpdGggYSBCYXllcyBmYWN0b3Igb2YgYHIgcm91bmQoZXh0cmFjdEJGKGJmS2FuYWlOdWxsWzFdLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMSlgLiBXZSBjYW4gY29tcHV0ZSB0aGUgZXZpZGVuY2UgZm9yIGEgcGFydGljdWxhciBlZmZlY3QgYnkgY29tcGFyaW5nIHRoaXMgd2lubmluZyBtb2RlbCB3aXRoIHRoZSBiZXN0LWZpdHRpbmcgbW9kZWwgdGhhdCBkb2VzIF9ub3RfIGNvbnRhaW4gdGhlIGVmZmVjdC4gV2UgY2FuIGNvbXB1dGUgdGhlIGV2aWRlbmNlIGZvciBfYWJzZW5jZV8gb2YgYSBwYXJ0aWN1bGFyIGVmZmVjdCBieSBjb21wYXJpbmcgdGhlIHdpbm5pbmcgbW9kZWwgd2l0aCB0aGUgYmVzdC1maXR0aW5nIG1vZGVsIHRoYXQgX2RvZXNfIGNvbnRhaW4gdGhlIGVmZmVjdC4KCiogU1RJTVVMQVRJT04uIFRoaXMgZWZmZWN0IGNhbiBiZSBxdWFudGlmaWVkIGJ5IGNvbXBhcmluZyB0aGUgQmF5ZXMgZmFjdG9ycyBvZiB0aGUgZmlyc3QgYW5kIHRoZSAzcmQgbW9kZWwgOiBgciByb3VuZChleHRyYWN0QkYoYmZLYW5haU51bGxbMV0gLyBiZkthbmFpTnVsbFszXSwgb25seWJmID0gVFJVRSksIGRpZ2l0cyA9IDEpYC4gVGhpcyBjb25zdGl0dWVzIF9fbW9kZXJhdGUgZXZpZGVuY2UgZm9yIHRoZSBwcmVzZW5jZSBvZiBhIHN0aW11bGF0aW9uIGVmZmVjdF9fLgoqIERJUkVDVElPTi4gVGhpcyBlZmZlY3QgY2FuIGJlIHF1YW50aWZpZWQgYnkgY29tcGFyaW5nIHRoZSBmaXJzdCBhbmQgdGhlIDJuZCBtb2RlbCA6IGByIHJvdW5kKGV4dHJhY3RCRihiZkthbmFpTnVsbFsxXSAvIGJmS2FuYWlOdWxsWzJdLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMSlgLiBUaGlzIGNvbnN0aXR1ZXMgX19hbmVjZG90YWwgZXZpZGVuY2UgZm9yIHRoZSBwcmVzZW5jZSBvZiBhIGRpcmVjdGlvbiBlZmZlY3RfXy4KCiogSW50ZXJhY3Rpb24gb2YgU1RJTVVMQVRJT04gYW5kIERJUkVDVElPTi4gVGhpcyB0ZXJtIGlzIG5vdCBpbiB0aGUgd2lubmluZyBtb2RlbCwgYW5kIGZpcnN0IHNob3dzIHVwIGluIHRoZSBmb3VydGggbW9kZWwuIFRoZSBCYXllcyBmYWN0b3IgZm9yIHRoZSBjb21wYXJpc29uIG9mIGJvdGggbW9kZWxzIGlzIGByIHJvdW5kKGV4dHJhY3RCRihiZkthbmFpTnVsbFsxXSAvIGJmS2FuYWlOdWxsWzRdLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMSlgLiBUaGlzIGNvbnN0aXR1ZXMgX19tb2RlcmF0ZSBldmlkZW5jZSBmb3IgdGhlIGFic2VuY2Ugb2YgYW4gaW50ZXJhY3Rpb24gYmV0d2VlbiBzdGltdWxhdGlvbiBhbmQgZGlyZWN0aW9uX18uCiogSW50ZXJhY3Rpb24gb2YgU1RJTVVMQVRJT04sIGFuZCBMRUcuIEJheWVzIGZhY3RvcjogYHIgcm91bmQoZXh0cmFjdEJGKGJmS2FuYWlOdWxsWzFdIC8gYmZLYW5haU51bGxbOF0sIG9ubHliZiA9IFRSVUUpLCBkaWdpdHMgPSAxKWAuIFRoaXMgY29uc3RpdHV0ZXMgX19tb2RlcmF0ZSBldmlkZW5jZSBmb3IgdGhlIGFic2VuY2Ugb2YgYW4gaW50ZXJhY3Rpb24gYmV0d2VlbiBzdGltdWxhdGlvbiBhbmQgbGVnX18uCiogVGhyZWUtd2F5IGludGVyYWN0aW9uLiBCYXllcyBmYWN0b3I6IGByIHJvdW5kKGV4dHJhY3RCRihiZkthbmFpTnVsbFsxXSAvIGJmS2FuYWlOdWxsWzE4XSwgb25seWJmID0gVFJVRSksIGRpZ2l0cyA9IDEpYC4gVGhpcyBjb25zdGl0dXRlcyBfX3N0cm9uZyBldmlkZW5jZSBmb3IgdGhlIGFic2VuY2Ugb2YgYW4gaW50ZXJhY3Rpb24gYmV0d2VlbiBzdGltdWxhdGlvbiwgbGVnIGFuZCBkaXJlY3Rpb25fXy4KCiMjIyMgVGVzdCBhZ2FpbnN0IHRoZSBmdWxsIG1vZGVsCgpBbm90aGVyIG9wdGlvbiBmb3IgcXVhbnRpZnlpbmcgZXZpZGVuY2UgZm9yIGEgcGFydGljdWxhciBlZmZlY3QgaXMgdG8gY29tcGFyZSB0aGUgZnVsbCBtb2RlbCB0byBhIG1vZGVsIHdoZXJlIHRoYXQgZWZmZWN0IGlzIG9taXR0ZWQgKGB3aGljaE1vZGVscyA9IHRvcCIpYC4gVGhlIGZ1bGwgbW9kZWwgaXMgYHN0aW11bGF0aW9uICsgZGlyZWN0aW9uICsgc3RpbXVsYXRpb246ZGlyZWN0aW9uICsgbGVnICsgc3RpbXVsYXRpb246bGVnICsgZGlyZWN0aW9uOmxlZyArIHN0aW11bGF0aW9uOmRpcmVjdGlvbjpsZWcgKyBzdWJqZWN0YC4KCmBgYHtyIENvbXB1dGUgQmF5ZXMgRmFjdG9ycyBjZi4gZnVsbCBtb2RlbH0KYmZLYW5haUZ1bGwgPSBhbm92YUJGKGxhdGVuY3l+c3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbitzdWJqZWN0LCBkYXRhID0gZGF0YS5mcmFtZShsYXRlbmN5TWVkaWFuQmFzZWxpbmVMYXRlcmFsKSwgd2hpY2hNb2RlbHM9InRvcCIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAjIGNvbXB1dGUgQmF5ZXMgRmFjdG9ycwpiZkthbmFpRnVsbApgYGAKClJlbW92aW5nIHRoZSBESVJFQ1RJT04gZWZmZWN0IGZyb20gdGhlIG1vZGVsIHlpZWxkcyBhIGxvd2VyIEJheWVzIEZhY3Rvciwgc28gaW5jbHVkaW5nIHRoaXMgZWZmZWN0IGltcHJvdmVkIHRoZSBtb2RlbC4gVGhpcyB0aHVzIGNvbnN0aXR1ZXMgKHNvbWUpIGV2aWRlbmNlIGZvciB0aGUgYWx0ZXJuYXRpdmU6IGAgMSBcIGAgYHIgcm91bmQoZXh0cmFjdEJGKGJmS2FuYWlGdWxsWzZdLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMylgIGAgPSBgIGByIHJvdW5kKGV4dHJhY3RCRigxL2JmS2FuYWlGdWxsWzZdLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMSlgLiBUaGUgZXZpZGVuY2UgZm9yIGEgc3RpbXVsYXRpb24gZWZmZWN0IGlzIGFsc28gYWJvdXQgdGhlIHNhbWU6IGByIHJvdW5kKGV4dHJhY3RCRigxL2JmS2FuYWlGdWxsWzddLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMSlgLgoKT24gdGhlIGNvbnRyYXJ5LCByZW1vdmluZyB0aGUgaW50ZXJhY3Rpb25zIGFjdHVhbGx5IGltcHJvdmVzIHRoZSBtb2RlbCwgc28gdGhlcmUgaXMgbW9kZXJhdGUgZXZpZGVuY2UgZm9yIHRoZSBhYnNlbmNlIG9mIGludGVyYWN0aW9uIGVmZmVjdHMuCgpBbGwgaW4gYWxsLCBmb3IgbW9zdCBlZmZlY3RzLCB0aGUgcmVzdWx0IGlzIHF1YWxpdGF0aXZlbHkgc2ltaWxhciB0byB0aGUgYXBwcm9hY2ggb2YgdGVzdGluZyBhZ2FpbnN0IHRoZSBudWxsLW1vZGVsLiBPbmx5IHRoZSBldmlkZW5jZSBmb3IgYWJzZW5jZSBvZiB0aGUgdGhyZWUtd2F5IGludGVyYWN0aW9uIGlzIG11Y2gsIG11Y2ggc21hbGxlciBoZXJlLgoKIyMjIEJheWVzaWFuIGxpbmVhciBtaXhlZCBlZmZlY3RzIG1hdGNoaW5nIEthbmFpIC0gY2VudGVyIHNhY2NhZGVzCgpgYGB7ciBCYXllcyBGYWN0b3IgS2FuYWkgY2VudGVyfQpiZkthbmFpQ2VudGVyID0gYW5vdmFCRihsYXRlbmN5fnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUobGF0ZW5jeU1lZGlhbkJhc2VsaW5lQ2VudGVyKSwgd2hpY2hNb2RlbHM9InRvcCIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAjIGNvbXB1dGUgQmF5ZXMgRmFjdG9ycwpiZkthbmFpQ2VudGVyCmBgYAoKIyMjIEJheWVzaWFuIGxpbmVhciBtaXhlZCBlZmZlY3RzIHdpdGggYmFzZWxpbmUgLSBzYWNjYWRlIGxhdGVuY3kKClJlcGVhdCB0aGUgYW5hbHlzaXMgd2hlbiB0aGUgYmFzZWxpbmUgaXMgbm90IHN1YnRyYWN0ZWQsIGFuZCBhbHNvIGZvciBjZW50ZXIgc2FjY2FkZXMuCgojIyMjIExhdGVyYWwgc2FjY2FkZXMKCmBgYHtyIENvbXB1dGUgQmF5ZXMgRmFjdG9ycyBsYXRlcmFsIHdpdGgtYmFzZWxpbmUgbW9kZWx9CgojIGtlZXAgb25seSBsYXRlcmFsIHNhY2NhZGVzCmxhdGVuY3lNZWRpYW5MYXRlcmFsIDwtIGxhdGVuY3lNZWRpYW5MZWdFeGNsICU+JQogIGZpbHRlcih0eXBlID09ICJsYXRlcmFsIikgJT4lCiAgc2VsZWN0KC10eXBlKQogIApiZkxhdGVyYWwgPSBhbm92YUJGKGxhdGVuY3l+c3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbitzdWJqZWN0LCBkYXRhID0gZGF0YS5mcmFtZShsYXRlbmN5TWVkaWFuTGF0ZXJhbCksIHdoaWNoTW9kZWxzPSJ0b3AiLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZMYXRlcmFsCmBgYAoKV2hlbiBpbmNsdWRpbmcgdGhlIGJhc2VsaW5lLCB0aGUgZXZpZGVuY2UgZm9yIG51bGwgZWZmZWN0cyBhcmUgc3Ryb25nZXIgYWxsIGFyb3VuZC4KCiMjIyMgQ2VudGVyIHNhY2NhZGVzCgpgYGB7ciBDb21wdXRlIEJheWVzIEZhY3RvcnMgY2VudGVyIHdpdGgtYmFzZWxpbmUgbW9kZWx9CgojIGtlZXAgb25seSBjZW50ZXIgc2FjY2FkZXMKbGF0ZW5jeU1lZGlhbkNlbnRlciA8LSBsYXRlbmN5TWVkaWFuTGVnRXhjbCAlPiUKICBmaWx0ZXIodHlwZSA9PSAiY2VudGVyIikgJT4lCiAgc2VsZWN0KC10eXBlKQogIApiZkNlbnRlciA9IGFub3ZhQkYobGF0ZW5jeX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKGxhdGVuY3lNZWRpYW5DZW50ZXIpLCB3aGljaE1vZGVscz0idG9wIiwgd2hpY2hSYW5kb20gPSAic3ViamVjdCIsIHByb2dyZXNzID0gRkFMU0UsIGl0ZXJhdGlvbnMgPSAxMDAwMDApICMgY29tcHV0ZSBCYXllcyBGYWN0b3JzCmJmQ2VudGVyCmBgYAoKTm93IHRoZSBtb2RlbCBpbXByb3ZlcyBhbGwgdGhlIHRpbWUsIG5vIG1hdHRlciB3aGljaCBlZmZlY3QgaXMgb21pdHRlZC4KCiMgUmVhY3Rpb24gdGltZSBkaXN0cmlidXRpb25zCgojIyBTcGxpdCBkYXRhIGluIGVxdWFsIGJsb2NrcwoKV2Ugd2FudCB0aGUgc2FtZSBudW1iZXIgb2YgdHJpYWxzIHRvIGdvIGludG8gZWFjaCBkaXN0cmlidXRpb24sIHNvIHdlJ2xsIHNwbGl0IHRoZSAzMC1taW51dGUgbG9uZyBgcG9zdGAgbGVnIGludG8gdHdvLiBUaGVuIHdlIGhhdmUgNCAxNS1taW51dGUgbG9uZyBkYXRhIHNlZ21lbnRzOiBgcHJlYCwgYHREQ1NgLCBgcG9zdC4xYCBhbmQgYHBvc3QuMmAuCgpgYGB7ciBDcmVhdGUgNCBsZWdzfQojIEdyb3VwIHNpbmdsZS10cmlhbCBkYXRhIGluIDQgbGVncyBpbnN0ZWFkIG9mIDMKZ3JvdXBEYXRhQmxvY2tlZCA8LSBncm91cERhdGEgJT4lCiAgbXV0YXRlKGxlZyA9IGFzLmNoYXJhY3RlcihsZWcpKSAlPiUgI3VuLWZhY3RvciB0aGUgbGVnIGNvbHVtbiBzbyB3ZSBjYW4gY2hhbmdlIGl0CiAgbXV0YXRlKGxlZz1yZXBsYWNlKGxlZywgbGVnID09ICJwb3N0IiwgInBvc3QuMSIpLCAjIHNwbGl0IHRoZSAicG9zdCIgbGV2ZWwgaW50byB0d28KICAgICAgICAgbGVnPXJlcGxhY2UobGVnLCBibG9jayA+IDMsICJwb3N0LjIiKSkgJT4lCiAgbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoInByZSIsInREQ1MiLCJwb3N0LjEiLCJwb3N0LjIiKSkpICNyZS1mYWN0b3IKYGBgCgojIyBGaXQgdGhlIG1vZGVsCgpOZXh0IHdlIGZpdCBhbiBleC1nYXVzc2lhbiBkaXN0cmlidXRpb24gdXNpbmcgdGhlIGByZXRpbWVzYCBwYWNrYWdlLiBPbmUgbW9kZWwgaXMgZml0IGZvciBlYWNoIGNvbWJpbmF0aW9uIG9mOgoKKiBTVUJKRUNUIChTMDEsIFMwMiwgZXRjLikKKiBTVElNVUxBVElPTiAoYW5vZGFsLCBjYXRob2RhbCkKKiBMRUcgKHByZSwgdERDUywgcG9zdC4xLCBwb3N0LjIpCiogVFlQRSAoY2VudGVyLCBsYXRlcmFsKQoqIERJUkVDVElPTiAobGVmdCwgcmlnaHQpCgpUaGUgZXgtZ2F1c3NpYW4gZGlzdHJpYnV0aW9uIGlzIHRoZSBjb252b2x1dGlvbiBvZiBhIG5vcm1hbCBhbmQgYW4gZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLiBJdCBjYW4gYmUgY2hhcmFjdGVyaXplZCB3aXRoIDMgcGFyYW1ldGVyczoKCiogJFxtdSQgKF9tdV8pOiB0aGUgbWVhbiBvZiB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbgoqICRcc2lnbWEkIChfc2lnbWFfKTogdGhlIHZhcmlhbmNlIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uCiogJFx0YXUkIChfdGF1Xyk6IHRoZSByYXRlIHBhcmFtZXRlciBvZiB0aGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uCgpXZSdsbCBkbyBtaW5pbWFsIHByZS1wcm9jZXNzaW5nOiBrZWVwIGFsbCBzdWJqZWN0cywgb25seSBkaXNjYXJkIG5lZ2F0aXZlIFJUcwoKYGBge3IgRml0IGV4LWdhdXNzaWFufQpncm91cERhdGFGaXQgPC0gZ3JvdXBEYXRhQmxvY2tlZCAlPiUKICBmaWx0ZXIobGF0ZW5jeSA+IDApICU+JSAjIHRocm93IG91dCBtaXNzaW5nIGFuZCBuZWdhdGl2ZSBSVHMKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGxlZyx0eXBlLGRpcmVjdGlvbikgJT4lICMgZm9yIGV2ZXJ5IGNvbmRpdGlvbgogIHN1bW1hcmlzZShyZXN1bHQgPSBsaXN0KGRhdGEuZnJhbWUodChhdHRyKHRpbWVmaXQobGF0ZW5jeSksInBhciIpKSkpKSAlPiUgIyBbc2VlIGJlbG93XQogIHVuZ3JvdXAoKSAlPiUgIyByZW1vdmUgZ3JvdXBpbmcgaW5mb3JtYXRpb24gKG90aGVyd2lzZSB1bm5lc3Qgd2lsbCBub3Qgd29yaykKICB1bm5lc3QoKSAjIHVucGFjayB0aGUgbGlzdCBjb2x1bW4sIHNvIGVhY2ggcGFyYW1ldGVyIGdldHMgaXRzIG93biBjb2x1bW4KICAKIyAxLiBmaXQgdGhlIGV4LWdhdXNzaWFuIHRvIHRoZSBsYXRlbmN5IGRhdGEgd2l0aCB0aGUgdGltZWZpdCgpIGZ1bmN0aW9uCiMgMi4gZXh0cmFjdCB0aGUgZml0dGVkIHBhcmFtZXRlcnMgZnJvbSB0aGUgcmVzdWx0aW5nIG9iamVjdCB3aXRoICJhdHRyKCkiCiMgMy4gdHJhbnNwb3NlICgidCgpIikgc28gZXZlcnkgcGFyYW1ldGVyIGlzIGluIGEgZGlmZmVyZW50IGNvbHVtbgojIDQuIGNvbnZlcnQgdG8gYSBkYXRhIGZyYW1lIHdpdGggb25lIGNvbHVtbiBwZXIgcGFyYW1ldGVyCiMgNS4gcGFjayBpbiBhIGxpc3Qgc28gd2UgaGF2ZSBzb21ldGhpbmcgb2Ygc2l6ZSAxIHdlIGNhbiBhc3NpZ24gdG8gdGhlIGRhdGFmcmFtZQojICJyZXN1bHQiIGlzIG5vdyBhIGxpc3QtY29sdW1uLCB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgYSBkYXRhZnJhbWUgd2l0aCBlc3RpbWF0ZXMgb2YgdGhlIDMgcGFyYW1ldGVycwoKIyBBbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBmdW5jdGlvbiB0byBmaXQgdGhlIGRhdGEsIGFuZCB0aGVuIGNhbGwgaXQgdGhyb3VnaCBkcGx5cjo6ZG8KI215RnVuYyA8LSBmdW5jdGlvbih4KXsKIyAgZGF0YS5mcmFtZSh0KGF0dHIodGltZWZpdCh4KSwicGFyIikpKQojfQojZ3JvdXBEYXRhRml0IDwtIGdyb3VwRGF0YUJsb2NrZWQgJT4lCiMgIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24sbGVnLHR5cGUsZGlyZWN0aW9uKSAlPiUgIyBmb3IgZXZlcnkgY29uZGl0aW9uCiMgIGRvKChteUZ1bmMoLiRsYXRlbmN5KSkpCmBgYAoKIyMgSW5zcGVjdCBmaXR0ZWQgcGFyYW1ldGVycwoKYGBge3IgSW5zcGVjdCBmaXR0ZWQgbXUgcGFyYW1ldGVyLCBmaWcud2lkdGggPSA5LjZ9CmdncGxvdChncm91cERhdGFGaXQsIGFlcyhpbnRlcmFjdGlvbihsZWcsc3RpbXVsYXRpb24pLCBtdSwgY29sb3IgPSBzdWJqZWN0KSkgKwogIGZhY2V0X2dyaWQodHlwZX5kaXJlY3Rpb24pICsgCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZnVuLnltaW4gPSBmdW5jdGlvbih4KSBtZWFuKHgpIC0gMipzZCh4KSwgZnVuLnltYXggPSBmdW5jdGlvbih4KSBtZWFuKHgpICsgMipzZCh4KSwgYWVzKGdyb3VwID0gMSkpICsgIyBwbG90IG1lYW4gYW5kIDIqU0QgdG8gd2F0Y2ggZm9yIG91dGxpZXJzOyB3ZSBuZWVkIGdyb3VwID0gMSBiZWNhdXNlIHRoZSB4LWF4aXMgaXMgYSBjb21iaW5hdGlvbiBvZiBmYWN0b3JzCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjYpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKYGBgCgpGb3IgY2VudGVyIHNhY2NhZGVzIHNvbWUgZXN0aW1hdGVzIG9mICRcbXUkIGFyZSBzaW1wbHkgdG9vIGZhc3QgKGUuZy4gUzA5KTsgdGhleSByZWZsZWN0IHByZW1hdHVyZSBleWUgbW92ZW1lbnRzLiBUaGUgZGlzdHJpYnV0aW9uIGlzIGFsc28gbm90IGEgZ29vZCBmaXQgaW4gdGhlc2UgY2FzZXMuCgpGb3IgY2VudGVyIHNhY2NhZGVzLCBpdCBsb29rcyByZWFzb25hYmxlLiBTMDEgaXMgbW9yZSB0aGFuIDIgU0QgYXdheSBmcm9tIHRoZSBtZWFuLCBidXQgdGhlIGZpdCBpcyBleGNlbGxlbnQuCgpgYGB7ciBJbnNwZWN0IGZpdHRlZCBzaWdtYSBwYXJhbWV0ZXIsIGZpZy53aWR0aCA9IDkuNn0KZ2dwbG90KGdyb3VwRGF0YUZpdCwgYWVzKGludGVyYWN0aW9uKGxlZyxzdGltdWxhdGlvbiksIHNpZ21hLCBjb2xvciA9IHN1YmplY3QpKSArCiAgZmFjZXRfZ3JpZCh0eXBlfmRpcmVjdGlvbikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGZ1bi55bWluID0gZnVuY3Rpb24oeCkgbWVhbih4KSAtIDIqc2QoeCksIGZ1bi55bWF4ID0gZnVuY3Rpb24oeCkgbWVhbih4KSArIDIqc2QoeCksIGFlcyhncm91cCA9IDEpKSArCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjYpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKYGBgCgpDZW50ZXIgc2FjY2FkZXMgYXBwZWFyIHRvIGhhdmUgbGFyZ2VyICRcc2lnbWEkIHRoYW4gbGF0ZXJhbC4gQnV0IGlmIHlvdSBpbnNwZWN0IHRoZSBkaXN0cmlidXRpb25zLCB0aGUgcGVhayBpcyBhY3R1YWxseSBtdWNoIHNoYXJwZXIsIHdoaWNoIHNob3VsZCBpbmRpY2F0ZSBsb3dlciB2YXJpYW5jZS4gVGhlIHByb2JsZW0gaXMgdGhhdCB0aGUgc2hhcGUgb2YgbWFueSBkaXN0cmlidXRpb25zIGRvZXMgbm90IGNvbmZvcm0gd2VsbDogbWFueSBzYWNjYWRlcyBhcmUgZWFybHkgYW5kIGhhdmUgbGl0dGxlIHZhcmlhbmNlLCBidXQgdGhlbiB0aGVyZSdzIGFsc28gYSBidW1wIGluIHRoZSByaWdodC10YWlsIHdoaWNoIGNhdXNlcyB0aGUgc2lnbWEtcGFyYW1ldGVyIHRvIGluY3JlYXNlLgoKVmFsdWVzIGZvciB0aGUgbGF0ZXJhbCBkaXN0cmlidXRpb24gc2VlbSByZWFzb25hYmxlLiAyIGVzdGltYXRlcyBvZiAkXHNpZ21hJCBhcmUgdG9vIGNsb3NlIHRvIHplcm8sIG90aGVycyBhcmUgdG9vIGhpZ2gsIGJ1dCB0aGUgc3ByZWFkIGlzIG5vdCB1bnJlYXNvbmFibGUuIEluc3BlY3RpbmcgdGhlc2UgZGlzdHJpYnV0aW9ucyBhbHNvIHJldmVhbHMgcHJlc2VuY2Ugb2YgYSAic2hvdWxkZXIiIHJpZ2h0IG9mIHRoZSBwZWFrLCB3aGljaCBjYW4gZWl0aGVyIHNwcmVhZCB0aGUgZGlzdHJpYnV0aW9uIG91dCBvciBuYXJyb3cgaXQgdG9vIG11Y2guCgpgYGB7ciBJbnNwZWN0IGZpdHRlZCB0YXUgcGFyYW1ldGVyLCBmaWcud2lkdGggPSA5LjZ9CmdncGxvdChncm91cERhdGFGaXQsIGFlcyhpbnRlcmFjdGlvbihsZWcsc3RpbXVsYXRpb24pLCB0YXUsIGNvbG9yID0gc3ViamVjdCkpICsKICBmYWNldF9ncmlkKHR5cGV+ZGlyZWN0aW9uKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZnVuLnltaW4gPSBmdW5jdGlvbih4KSBtZWFuKHgpIC0gMipzZCh4KSwgZnVuLnltYXggPSBmdW5jdGlvbih4KSBtZWFuKHgpICsgMipzZCh4KSwgYWVzKGdyb3VwID0gMSkpICsKICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuNikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKQpgYGAKClBhcnRpY3VsYXJseSBmb3IgY2VudGVyIHNhY2NhZGVzLCAkXHRhdSQgaXMgbWFueSB0aW1lcyBlc3RpbWF0ZWQgYXQgMC4gVGhpcyBtZWFucyB0aGF0IHRoZSBkaXN0cmlidXRpb24gaXMgYWN0dWFsbHkganVzdCBhIG5vcm1hbCBkaXN0cmlidXRpb24uIEZvciBjZW50ZXIgc2FjY2FkZXMgdGhhdCBtYWtlcyBzZW5zZSwgYXMgJFx0YXUkIGlzIHJlc3BvbnNpYmxlIGZvciB0aGUgbG9uZ2VyIHJpZ2h0IHRhaWwgdGhhdCBjaGFyYWN0ZXJpemVzIHRoZSBleC1nYXVzc2lhbiBkaXN0cmlidXRpb24uIFdoZW4gc2FjY2FkZXMgYXJlIGFsbCBzdXBlciBmYXN0LCB0aGlzIHRhaWwgaXMgbm90IHByZXNlbnQuCgojIyBNdQoKIyMjIFBsb3QKCmBgYHtyIG11IHBsb3R9Cm11TGluZVBsb3QgPC0gZ2dwbG90KGdyb3VwRGF0YUZpdCwgYWVzKGxlZywgbXUsIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gc3RpbXVsYXRpb24pKSArICAgICAgICAgCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAzKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBzaXplID0gMSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjMpCm11TGluZVBsb3QKYGBgCgojIyMgU3RhdGlzdGljcwoKIyMjIyBMYXRlcmFsCgpgYGB7cn0KbXVMYXRlcmFsIDwtIGdyb3VwRGF0YUZpdCAlPiUKICBmaWx0ZXIodHlwZSA9PSAibGF0ZXJhbCIpICU+JQogIHNlbGVjdCgtdHlwZSkKYGBgCgpgYGB7ciBtdSBsYXRlcmFsIGFub3ZhLCByZXN1bHRzID0gJ2FzaXMnfQptb2RlbE11TGF0ZXJhbCA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKG11TGF0ZXJhbCksIGR2ID0gLihtdSksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sIGxlZywgZGlyZWN0aW9uKSwgdHlwZSA9IDMpCmthYmxlKG1vZGVsTXVMYXRlcmFsJEFOT1ZBKQpgYGAKCmBgYHtyIG11IGxhdGVyYWwgQmF5ZXN9CmJmTXVMYXRlcmFsID0gYW5vdmFCRihtdX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKG11TGF0ZXJhbCksIHdoaWNoTW9kZWxzPSJ0b3AiLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZNdUxhdGVyYWwKYGBgCgojIyMjIENlbnRlcgoKYGBge3J9Cm11Q2VudGVyIDwtIGdyb3VwRGF0YUZpdCAlPiUKICBmaWx0ZXIodHlwZSA9PSAiY2VudGVyIikgJT4lCiAgc2VsZWN0KC10eXBlKQpgYGAKCmBgYHtyIG11IGNlbnRlciBhbm92YSwgcmVzdWx0cyA9ICdhc2lzJ30KbW9kZWxNdUNlbnRlciA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKG11Q2VudGVyKSwgZHYgPSAuKG11KSwgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbiwgbGVnLCBkaXJlY3Rpb24pLCB0eXBlID0gMykKa2FibGUobW9kZWxNdUNlbnRlciRBTk9WQSkKYGBgCgpgYGB7ciBtdSBjZW50ZXIgQmF5ZXN9CmJmTXVDZW50ZXIgPSBhbm92YUJGKG11fnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUobXVDZW50ZXIpLCB3aGljaE1vZGVscz0idG9wIiwgd2hpY2hSYW5kb20gPSAic3ViamVjdCIsIHByb2dyZXNzID0gRkFMU0UsIGl0ZXJhdGlvbnMgPSAxMDAwMDApICMgY29tcHV0ZSBCYXllcyBGYWN0b3JzCmJmTXVDZW50ZXIKYGBgCgojIyBTaWdtYQoKIyMjIFBsb3QKCmBgYHtyIHNpZ21hIHBsb3R9CnNpZ21hTGluZVBsb3QgPC0gZ2dwbG90KGdyb3VwRGF0YUZpdCwgYWVzKGxlZywgc2lnbWEsIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gc3RpbXVsYXRpb24pKSArICAgICAgICAgCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAzKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBzaXplID0gMSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjMpCnNpZ21hTGluZVBsb3QKYGBgCgojIyMgU3RhdGlzdGljcwoKIyMjIyBMYXRlcmFsCgpgYGB7cn0Kc2lnbWFMYXRlcmFsIDwtIGdyb3VwRGF0YUZpdCAlPiUKICBmaWx0ZXIodHlwZSA9PSAibGF0ZXJhbCIpICU+JQogIHNlbGVjdCgtdHlwZSkKYGBgCgpgYGB7ciBzaWdtYSBsYXRlcmFsIGFub3ZhLCByZXN1bHRzID0gJ2FzaXMnfQptb2RlbFNpZ21hTGF0ZXJhbCA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKHNpZ21hTGF0ZXJhbCksIGR2ID0gLihzaWdtYSksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sIGxlZywgZGlyZWN0aW9uKSwgdHlwZSA9IDMpCmthYmxlKG1vZGVsU2lnbWFMYXRlcmFsJEFOT1ZBKQpgYGAKCmBgYHtyIHNpZ21hIGxhdGVyYWwgQmF5ZXN9CmJmU2lnbWFMYXRlcmFsID0gYW5vdmFCRihzaWdtYX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKHNpZ21hTGF0ZXJhbCksIHdoaWNoTW9kZWxzPSJ0b3AiLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZTaWdtYUxhdGVyYWwKYGBgCgojIyMjIENlbnRlcgoKYGBge3J9CnNpZ21hQ2VudGVyIDwtIGdyb3VwRGF0YUZpdCAlPiUKICBmaWx0ZXIodHlwZSA9PSAiY2VudGVyIikgJT4lCiAgc2VsZWN0KC10eXBlKQpgYGAKCmBgYHtyIHNpZ21hIGNlbnRlciBhbm92YSwgcmVzdWx0cyA9ICdhc2lzJ30KbW9kZWxTaWdtYUNlbnRlciA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKHNpZ21hQ2VudGVyKSwgZHYgPSAuKHNpZ21hKSwgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbiwgbGVnLCBkaXJlY3Rpb24pLCB0eXBlID0gMykKa2FibGUobW9kZWxTaWdtYUNlbnRlciRBTk9WQSkKYGBgCgpgYGB7ciBzaWdtYSBjZW50ZXIgQmF5ZXN9CmJmU2lnbWFDZW50ZXIgPSBhbm92YUJGKHNpZ21hfnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUoc2lnbWFDZW50ZXIpLCB3aGljaE1vZGVscz0idG9wIiwgd2hpY2hSYW5kb20gPSAic3ViamVjdCIsIHByb2dyZXNzID0gRkFMU0UsIGl0ZXJhdGlvbnMgPSAxMDAwMDApICMgY29tcHV0ZSBCYXllcyBGYWN0b3JzCmJmU2lnbWFDZW50ZXIKYGBgCgojIyBUYXUKCiMjIyBQbG90CgpgYGB7ciB0YXUgcGxvdH0KdGF1TGluZVBsb3QgPC0gZ2dwbG90KGdyb3VwRGF0YUZpdCwgYWVzKGxlZywgdGF1LCBjb2xvciA9IHN0aW11bGF0aW9uLCBzaGFwZSA9IHN0aW11bGF0aW9uKSkgKyAgICAgICAgIAogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaXplID0gMykgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgc2l6ZSA9IDEpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC4zKQp0YXVMaW5lUGxvdApgYGAKCiMjIyBTdGF0aXN0aWNzCgojIyMjIExhdGVyYWwKCmBgYHtyfQp0YXVMYXRlcmFsIDwtIGdyb3VwRGF0YUZpdCAlPiUKICBmaWx0ZXIodHlwZSA9PSAibGF0ZXJhbCIpICU+JQogIHNlbGVjdCgtdHlwZSkKYGBgCgpgYGB7ciB0YXUgbGF0ZXJhbCBhbm92YSwgcmVzdWx0cyA9ICdhc2lzJ30KbW9kZWxUYXVMYXRlcmFsIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUodGF1TGF0ZXJhbCksIGR2ID0gLih0YXUpLCB3aWQgPSAuKHN1YmplY3QpLCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLCBsZWcsIGRpcmVjdGlvbiksIHR5cGUgPSAzKQprYWJsZShtb2RlbFRhdUxhdGVyYWwkQU5PVkEpCmBgYAoKYGBge3IgdGF1IGxhdGVyYWwgQmF5ZXN9CmJmVGF1TGF0ZXJhbCA9IGFub3ZhQkYodGF1fnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUodGF1TGF0ZXJhbCksIHdoaWNoTW9kZWxzPSJ0b3AiLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZUYXVMYXRlcmFsCmBgYAoKIyMjIyBDZW50ZXIKCmBgYHtyfQp0YXVDZW50ZXIgPC0gZ3JvdXBEYXRhRml0ICU+JQogIGZpbHRlcih0eXBlID09ICJjZW50ZXIiKSAlPiUKICBzZWxlY3QoLXR5cGUpCmBgYAoKYGBge3IgdGF1IGNlbnRlciBhbm92YSwgcmVzdWx0cyA9ICdhc2lzJ30KbW9kZWxUYXVDZW50ZXIgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZSh0YXVDZW50ZXIpLCBkdiA9IC4odGF1KSwgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbiwgbGVnLCBkaXJlY3Rpb24pLCB0eXBlID0gMykKa2FibGUobW9kZWxUYXVDZW50ZXIkQU5PVkEpCmBgYAoKYGBge3IgdGF1IGNlbnRlciBCYXllc30KYmZUYXVDZW50ZXIgPSBhbm92YUJGKHRhdX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKHRhdUNlbnRlciksIHdoaWNoTW9kZWxzPSJ0b3AiLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZUYXVDZW50ZXIKYGBgCg==